HDU6181 Two Paths(次短路,路径记录,spfa,2017 HDU多校联赛 第10场)
来源:互联网 发布:数据库一致性 编辑:程序博客网 时间:2024/05/18 03:38
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
23 31 2 12 3 41 3 32 11 2 1
Sample Output
53
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
思路
题意:
给出一个无向图,有n个点m条边和对应的权值,每两个点之间最多只有一条路。有两个人要从1号点走到n号点,第一个人走的是最短路径,第二个人也要走尽量短的路(次短路),但是要注意第二个人走的路径不能和第一个人相同,所以在第二组样例中,他先从1走到2,然后返回1,然后再走到2。
分析:
首先我们要求出次短路,我们求次短路的方法是:以点1为起点进行一遍spfa,再以点n为起点,进行一遍spfa,然后枚举除了1和n之外的所有点,找出从1~x的最短距离+从n~x的最短距离最小的那个值,这个值就是次短路。枚举的时候要注意:如果当前枚举的点在最短路径上出现过,那么就不枚举当前点,跳过。
当我们求出次短路以后,我们要判断当前的次短路是不是等于INF
:
1. 如果等于的话,那么现在我们要在最短路径上的点的出边及最短路径上的边中找一条边走两次,设这一条边的长度为minnc
,最短路径为dis[n]
,那么现在第二个人走的路径是dis[n]+2*minc
2. 如果不等于的话,我们要取次短路和在最短路的基础上把一条边走两次的最小值
解释一下为什么要在最短路及最短路的每个点的出边上找minc
如上图,当我们很容易看出从1~6的最短路为30,那么我们要把一条路走两次的话,如果仅仅的在最短路上找边的话只能找到10把10走两次,这样得到的结果是50,很明显这样是错误的,我们要找的是2,如果把2走两次的话,那么得到的结果是34,很明显,要在最短路上和其中每个点的出边找要走两次的那条边
代码
#include <cstdio>#include <cstring>#include <cctype>#include <string>#include <set>#include <iostream>#include <stack>#include <cmath>#include <queue>#include <vector>#include <algorithm>#define mem(a,b) memset(a,b,sizeof(a))#define mod 1000007#define M 12357#define ll long longusing namespace std;const ll N=100000+100;const ll inf=1e18;ll n,m,a,b,c,t;struct SPFA{ ll first[N*4],len,vis[N],dis[N],inq[N],pre[N]; vector<ll>path; void init() { mem(first,-1); mem(vis,0); mem(dis,0); mem(inq,0);//记录当前点是不是最短路径上的点 len=1; path.clear(); pre[1]=-1; } struct node { ll u,v,w,next; } G[N*4]; void add_edge(ll u,ll v,ll w) { G[len].v=v,G[len].w=w; G[len].next=first[u]; first[u]=len++; } void spfa(ll st) { for(ll i=1; i<=n; i++) { dis[i]=inf; vis[i]=0; } dis[st]=0; vis[st]=1; queue<ll>q; q.push(st); while(!q.empty()) { st=q.front(); q.pop(); vis[st]=0; for(ll i=first[st]; i!=-1; i=G[i].next) { ll v=G[i].v,w=G[i].w; if(dis[v]>dis[st]+w) { pre[v]=st; dis[v]=dis[st]+w; if(!vis[v]) { vis[v]=1; q.push(v); } } } } } void print_path(int x) { if(pre[x]!=-1) { print_path(pre[x]); inq[x]=1; path.push_back(x); } }} s1,s2;int main(){ ll t; scanf("%lld",&t); while(t--) { scanf("%lld%lld",&n,&m); s1.init(); s2.init(); for(ll i=1; i<=m; i++) { scanf("%lld%lld%lld",&a,&b,&c); s1.add_edge(a,b,c); s1.add_edge(b,a,c); s2.add_edge(a,b,c); s2.add_edge(b,a,c); } s1.spfa(1); s1.print_path(n); s2.spfa(n); ll minn=inf,k=s1.dis[n]; for(ll i=2; i<=n-1; i++) { if(s1.dis[i]+s2.dis[i]<=minn) { if(s1.inq[i]&&s1.dis[i]+s2.dis[i]==k)//如果当前用来松弛的点是最短路中出现过的点 continue; minn=s1.dis[i]+s2.dis[i]; } } s1.path.push_back(1);//把1号点加入路径 ll minc=inf; for(ll i=0; i<s1.path.size(); ++i) { for(ll j=s1.first[s1.path[i]]; ~j; j=s1.G[j].next)//遍历最短路径上的点的出边 { ll w=s1.G[j].w; minc=min(minc,w);//找出最小的边 } } if(n==2) printf("%lld\n",3*s1.dis[n]); else { if(minn==inf) printf("%lld\n",s1.dis[n]+2*minc); else printf("%lld\n",min(minn,s1.dis[n]+2*minc)); } } return 0;}
- HDU6181 Two Paths(次短路,路径记录,spfa,2017 HDU多校联赛 第10场)
- HDU6181 Two Paths【次短路】
- hdu6181 Two Paths 次短路模板
- hdu6181 Two Paths(次短路)
- 2017 第十场多校训练 HDU 6181 Two Paths 次短路+Dijkstra
- HDU6181-Two Paths【A*算法or次短路】
- 2017多校联合第四场1011/hdu6181(次短路)
- hdu6181-启发式搜索A*|次短路模板|最短路枚举-Two Paths
- HDU6170 Two strings(dp,2017 HDU多校联赛 第9场)
- 【hdu6181】Two Paths(次短路----每条边经过不止一次)
- 2017 Multi-University Training Contest 10 1011 Two Paths HDU 6181 (次短路+最短路数量)
- HDU 6181 Two Paths (次短路)
- hdu 6181 Two Paths (次短路)
- hdu 6181 Two Paths(次短路)
- Hdu 6181 Two Paths【次短路】
- hdu-6181 Two Paths次短路
- HDU 6181 Two Paths 次短路
- hdu 6181 Two Paths (次短路)
- DrawerLayout简单使用
- 【C语言】【unix c】获取文件的元数据(软链接,硬链接)(meta data)
- JsonPath用法
- CoreJava——阶段测试题(二)
- js的单线程和异步
- HDU6181 Two Paths(次短路,路径记录,spfa,2017 HDU多校联赛 第10场)
- 关于ui-view最佳实践的疑惑
- C# Redis消息队列例子
- 事务处理的四大特性详解
- ORM(1)转载
- 阿里前端2018秋招笔试题:判断JSON对象是否有环
- Lua中function的几种赋值方法
- JZOJ2017.08.12 B组
- 数组只能在初始化时整体赋初值。以后再赋值只能逐一改变了