hdu 6181 Two Paths(最短路,spfa)

来源:互联网 发布:农村淘宝合伙人加盟 编辑:程序博客网 时间:2024/06/15 03:43

题目链接:传送门

Two Paths

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 153428/153428 K (Java/Others)
Total Submission(s): 971 Accepted Submission(s): 450

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

Source
2017 Multi-University Training Contest - Team 10

题目大意:n个点,m条边,每条边有一个权值,除最短路外,再找一条最短路。
要求:只要两个最短路中有一步不同,那么这两个最短路就不同。

如第二个样例:1——2为最短路,那么第二个最短路就是1——2——1——2,因为第二步和第四步不同(即使第一个最短路没有,第二步和第四步)。
还有最坑的样例:3个点,3条边,1-3  3   1-2 1  2-3 100
最短路为1-3,第二条最短路为1-2-1-3;

思路:找出最短路径,并记录,依次去掉最短路中的一步,并记录他们的最短路(这是不依靠原先的最短路),然后再寻找链接着最短路点的最短的那一条边,最短路加2*最短的边长(这是依靠原先的最短路,如上述讲的例子)。

#include<stdio.h>#include<queue>#include<string.h>#include<algorithm>using namespace std;#define LL long longconst LL inf=1e18+9;const int N=350015;struct node{    LL w;    int v;    int nex;} e[N*4];int firs[N*4],tot;void edge(int u,int v,LL w)//建立邻接表{    e[tot].w=w;    e[tot].v=v;    e[tot].nex=firs[u];    firs[u]=tot++;}LL dis[N];//记录最短路int vis[N];struct nodee{    int xia;//最短路的点    int lon;//到该点的路径的编号} lu[N];//记录最短路的路径int n,m;void spfa(int u,int flag)//求最短路{    for(int i=1; i<=n; i++)    {        dis[i]=inf;        vis[i]=0;    }    dis[u]=0;    vis[u]=1;    queue<int>q;    q.push(u);    while(!q.empty())    {        int p=q.front();        q.pop();        vis[p]=0;        for(int i=firs[p]; i!=-1; i=e[i].nex)        {            if(dis[p]+e[i].w<dis[e[i].v])            {                if(flag)//记录路径                {                    lu[e[i].v].xia=p;                    lu[e[i].v].lon=i;                }                dis[e[i].v]=dis[p]+e[i].w;                if(!vis[e[i].v])                {                    vis[e[i].v]=1;                    q.push(e[i].v);                }            }        }    }}int main(){    int t;    scanf("%d",&t);    while(t--)    {        memset(firs,-1,sizeof(firs));        scanf("%d%d",&n,&m);        tot=0;        for(int i=0; i<m; i++)        {            int a,b;            LL c;            scanf("%d%d%lld",&a,&b,&c);            edge(a,b,c);//无向边,建立邻接表            edge(b,a,c);        }        for(int i=0; i<=n; i++)//用邻接表记录路径            lu[i].xia=i;        spfa(1,1);        LL dd=dis[n];        LL maxx=inf;//与最短路上的点有关的最短的路        int f=n;        LL maxxx=inf;//记录第二条最短路        while(f!=lu[f].xia)//遍历最短路        {            int ff=lu[f].lon;            maxx=min(maxx,e[ff].w);            for(int i=firs[f]; i!=-1; i=e[i].nex)//寻找与最短路上点有关的最短的边长            {                maxx=min(maxx,e[i].w);            }            LL p=e[ff].w;            e[ff].w=inf;//先删去该路径            spfa(1,0);            e[ff].w=p;//恢复该路径            f=lu[f].xia;            maxxx=min(maxxx,dis[n]);        }        for(int i=firs[1]; i!=-1; i=e[i].nex)//寻找与起点1有关的最短的边长        {            maxx=min(maxx,e[i].w);        }        maxxx=min(maxxx,dd+maxx+maxx);        printf("%lld\n",maxxx);    }    return 0;}
原创粉丝点击