hdu6181 Two Paths(次短路)

来源:互联网 发布:电气接线仿真软件 编辑:程序博客网 时间:2024/05/21 09:19

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 longusing 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\n",ans2);    }    return 0;}