hdu6181 Two Paths(次短路)

Problem Description
You are given a undirected graph with n nodes (numbered from 1 to n) and m edges. Alice and Bob are now trying to play a game.
Both of them will take different route from 1 to n (not necessary simple).
Alice always moves first and she is so clever that take one of the shortest path from 1 to n.
Now is the Bob’s turn. Help Bob to take possible shortest route from 1 to n.
There’s neither multiple edges nor self-loops.
Two paths S and T are considered different if and only if there is an integer i, so that the i-th edge of S is not the same as the i-th edge of T or one of them doesn’t exist.

Input
The first line of input contains an integer T(1 <= T <= 15), the number of test cases.
The first line of each test case contains 2 integers n, m (2 <= n, m <= 100000), number of nodes and number of edges. Each of the next m lines contains 3 integers a, b, w (1 <= a, b <= n, 1 <= w <= 1000000000), this means that there’s an edge between node a and node b and its length is w.
It is guaranteed that there is at least one path from 1 to n.
Sum of n over all test cases is less than 250000 and sum of m over all test cases is less than 350000.

Output
For each test case print length of valid shortest path in one line.

Sample Input
2
3 3
1 2 1
2 3 4
1 3 3
2 1
1 2 1

Sample Output
5
3

Hint
For testcase 1, Alice take path 1 - 3 and its length is 3, and then Bob will take path 1 - 2 - 3 and its length is 5.
For testcase 2, Bob will take route 1 - 2 - 1 - 2 and its length is 3

分析:
这道题又和Tyvj1293不一样了,
我们必须找到一条最短路,因此每条路可以重复走

我一开始非常simple,认为如果只有一条路可以到达终点
那次短路就是dis[t]*3 (到达终点–回来–再次到达终点)

后来发现不是这么简单的,
那我们把最短路中的最短一条边重复走三遍不就行了吗
但是这样我们也可以hack掉:
这里写图片描述

那怎么办呢
我们不光要套一个次短路模板
同时还要再加一个特判,

找到与最短路径上的点有关的路径中最短的一条边,

重复走这条边就可以了

tip

做题的时候还是要多思考,
找到复杂的样例,从中探寻规律

这里写代码片
#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long

using namespace std;

const ll INF=1e16;
const int N=100010;
int q[N<<1],tou,wei,n,m,st[N],tot,pre[N],s,t;
struct node{
    int x,y,nxt;
    ll v;
};
node way[N*6];
ll dis[N],ans1,ans2;
bool p[N];

void add(int u,int w,int z)
{
    tot++;
    way[tot].x=u;way[tot].y=w;way[tot].v=(ll)z;way[tot].nxt=st[u];st[u]=tot;
    tot++;
    way[tot].x=w;way[tot].y=u;way[tot].v=(ll)z;way[tot].nxt=st[w];st[w]=tot;
}

ll spfa(int s,int t)
{
    for (int i=1;i<=n;i++) dis[i]=INF,p[i]=1,pre[i]=0;
    wei=tou=0;
    q[++wei]=s;
    dis[s]=0, p[s]=0;
    do
    {
        int r=q[++tou];
        for (int i=st[r];i;i=way[i].nxt)
            if (dis[way[i].y]>dis[r]+way[i].v)
            {
                dis[way[i].y]=dis[r]+way[i].v;
                pre[way[i].y]=i;
                if (p[way[i].y])
                {
                    p[way[i].y]=0;
                    q[++wei]=way[i].y;
                }
            }
        p[r]=1;
    }
    while (tou<wei);
    return dis[t];
}

ll spfa2(int s,int t)
{
    for (int i=1;i<=n;i++) dis[i]=INF,p[i]=1;
    wei=tou=0;
    q[++wei]=s;
    dis[s]=0, p[s]=0;
    do
    {
        int r=q[++tou];
        for (int i=st[r];i;i=way[i].nxt)
            if (dis[way[i].y]>dis[r]+way[i].v)
            {
                dis[way[i].y]=dis[r]+way[i].v;
                if (p[way[i].y])
                {
                    p[way[i].y]=0;
                    q[++wei]=way[i].y;
                }
            }
        p[r]=1;
    }
    while (tou<wei);
    return dis[t];
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        memset(st,0,sizeof(st));
        tot=0;
        scanf("%d%d",&n,&m);
        s=1; t=n;
        for (int i=1;i<=m;i++)
        {
            int u,w,z;
            scanf("%d%d%d",&u,&w,&z);
            add(u,w,z);
        }
        ans1=spfa(s,t); 

        ans2=INF;
        ll o=INF;
        for (int i=t;i!=s;i=way[pre[i]].x)
        {
            ll u=way[pre[i]].v;
            if (u<o) o=u;
            way[pre[i]].v=INF;
            ll an=spfa2(s,t);
            if (an<ans2&&an!=ans1) ans2=an;
            way[pre[i]].v=u; 

            if (way[pre[i]].x!=0)
                for (int j=st[way[pre[i]].x];j;j=way[j].nxt)
                    if (way[j].v<o) o=way[j].v; 
        }

        for (int j=st[t];j;j=way[j].nxt)
            if (way[j].v<o) o=way[j].v; 
        if (ans1+2*o<ans2) ans2=ans1+2*o;

        printf("%lld
",ans2);
    }
    return 0;
} 
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673232.html