Two Paths
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 153428/153428 K (Java/Others)
Total Submission(s): 613 Accepted Submission(s): 312
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.
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.
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才讲的K短路,第二天多校就考到这个。=-=
比较裸,直接用A*算法+Dij堆优化,不加堆优化的Dij会超时的,而且这个题数据边的w值会很大,所以所有的边的变量,中间累加的变量,数组存下的长度,最后的A*函数返回结果(一开始WA了很多次,就在这里,返回值也要long long,只顾改了变量了,白白WA了几发)都要设置成long long,第二个就是无向边了,建图和反向建图的两个数组都要push两次。这也是一开始反向建图少一个就WA。
#include <iostream> #include <algorithm> #include <vector> #include <cstring> #include <queue> #include <cstdio> #define MAXN 100010 #define INF (1LL<<62) using namespace std; typedef long long ll; typedef pair<int, ll> P; int N, M, S, T, K; ll dist[MAXN]; ll tdist[MAXN]; int cnt[MAXN]; bool f[MAXN]; vector<P> Adj[MAXN]; vector<P> Rev[MAXN]; struct Edge { int to; ll len; Edge(){} Edge(int t, ll l):to(t), len(l){} }; priority_queue<Edge> q; bool operator<(const Edge &a, const Edge &b) { return (a.len + dist[a.to]) > (b.len + dist[b.to]); } void dijkstra() { memset(dist, 0, sizeof(dist)); fill(tdist, tdist+MAXN, INF); tdist[T] = 0; while(!q.empty()) q.pop(); q.push(Edge(T, 0)); while (!q.empty()) { int x = q.top().to; ll d = q.top().len; q.pop(); if (tdist[x] < d) continue; for (int i = 0; i < Rev[x].size(); i++) { int y = Rev[x][i].first; ll len = Rev[x][i].second; if (d+ len < tdist[y]) { tdist[y] = d + len; q.push(Edge(y, tdist[y])); } } } for (int i = 1; i <= N; i++){ dist[i] = tdist[i]; } } //注意这里是long long的返回结果啊! ll aStar() { if (dist[S] == INF) return -1; while (!q.empty()) q.pop(); q.push(Edge(S, 0)); memset(cnt, 0, sizeof(cnt)); while (!q.empty()) { int x = q.top().to; ll d = q.top().len; q.pop(); cnt[x]++; if (cnt[T] == K) return d; if (cnt[x] > K) continue; for (int i = 0; i < Adj[x].size(); i++) { int y = Adj[x][i].first; ll len = Adj[x][i].second; q.push(Edge(y, d+len)); } } return -1; } int main() { // freopen("in.txt","r",stdin); std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int tt; cin>>tt; while(tt--) { //初始化,忘了就WA for(int i = 0; i <= N; i++) { Adj[i].clear(); Rev[i].clear(); } int a, b; ll t; cin >> N >> M; for (int i = 0; i < M; i++) { cin >> a >> b >> t; Adj[a].push_back(make_pair(b, t)); Adj[b].push_back(make_pair(a, t)); Rev[b].push_back(make_pair(a, t)); Rev[a].push_back(make_pair(b, t)); } S = 1; T = N; K = 2; // cin >> S >> T >> K; if (S == T) K++; dijkstra(); cout << aStar() << endl; } return 0; }
次短路做法,用的别人模版:
原理就是在存dis最短路的时候同时用另外一个数组存次短路,在最短路交换边和dis[]值得时候,次短路存下新交换的没最短边长的值即可。
#include<cstdio> #include<cstring> #include<queue> #include<functional> #include<vector> #include<algorithm> using namespace std; typedef long long int ll; #define MAXM 350010 #define MAXN 250010 #define INF 1223372036854775807 typedef pair<ll,int> pp; typedef struct node { int v; ll w; node(int tv=0,ll tw=0): v(tv),w(tw){}; }node; int n,m; vector<node> edge[MAXM]; ll dis[MAXN],dis2[MAXN]; //dis[i]表示最短路,dis2[i]表示次短路 void solve() { fill(dis+1,dis+n+1,INF); fill(dis2+1,dis2+n+1,INF); priority_queue<pp, vector<pp>, greater<pp> > q; //用优先队列加速搜索 dis[1]=0; q.push(pp(dis[1],1)); //second是该边指向(虽然是无向的)的顶点,first是这条边的权值 while(q.size()) { pp p=q.top(); q.pop(); int v=p.second; ll d=p.first; if(dis2[v]<d) continue; //如果当前取出的值不是到v的最短路或次短路就contniue,因为v->e的最短边和次短边一定是由->v的最短边和次短边+edge(v,e)得到 for(int i=0;i<edge[v].size();i++) { int e=edge[v][i].v; ll d2=d+edge[v][i].w; if(dis[e]>d2) { swap(dis[e],d2); q.push(pp(dis[e],e)); } if(dis2[e]>d2&&d2>dis[v]) //d2>dis[v]防止d2小于dis[v],这样v->e就变成负权边了,但可有可无 { dis2[e]=d2; q.push(pp(dis2[e],e)); } } } printf("%lld ",dis2[n]); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) edge[i].clear(); for(int i=0;i<m;i++) { int a,b; ll c; scanf("%d%d%lld",&a,&b,&c); edge[a].push_back(node(b,c)); edge[b].push_back(node(a,c)); } solve(); } }
另个版本,这个版本INF一定要long long 才能过,为什么啊??
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <queue> #define INF (1LL<<62) using namespace std; typedef long long ll; typedef pair<ll,int> P; struct edge{ int to; ll v; edge(int to,ll v):to(to),v(v){} edge(){} }; const int maxn = 100010; const int maxe = 100010; int V,E; vector<edge> g[maxn]; ll d[maxn],d2[maxn];//最短距离和次短距离 void dijkstra(int s) { priority_queue<P,vector<P>,greater<P> > pq; for(int i=1;i<=V;i++) { d[i]=INF; d2[i]=INF; } d[s]=0; pq.push(P(0,s)); while(pq.size()) { P nowe=pq.top();pq.pop(); if(nowe.first>d2[nowe.second]) continue; //如果这个距离比当前次短路长continue for(int v=0;v<(int)g[nowe.second].size();v++) { edge nexte=g[nowe.second][v]; ll dis=nowe.first+nexte.v; if(d[nexte.to]>dis) { swap(dis,d[nexte.to]); pq.push(P(d[nexte.to],nexte.to)); } if(d2[nexte.to]>dis&&d[nexte.to]<dis)//保证最短路是小于这个次短路的 { d2[nexte.to]=dis; pq.push(P(d2[nexte.to],nexte.to));//次短路的点进入pq } } } } int main() { // freopen("in.txt","r",stdin); int TT; scanf("%d",&TT); while(TT--) { int s;//起点 scanf("%d%d",&V,&E); { for(int i=1;i<=V;i++) g[i].clear(); for(int i=1;i<=E;i++) { int f,t; ll v; scanf("%d%d%I64d",&f,&t,&v); g[f].push_back(edge(t,v)); g[t].push_back(edge(f,v)); } s=1;//这题默认起点为1 dijkstra(s); printf("%I64d ",d2[V]); } } return 0; }