hdu 6181 Two Paths(最短路,spfa)

119 篇文章 1 订阅
113 篇文章 1 订阅

题目链接:传送门

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 long
const 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值