[USACO 07NOV]Cow Relays
Description
For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout the pasture.
Each trail connects two different intersections (1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000), each of which is the termination for at least two trails. The cows know the lengthi of each trail (1 ≤ lengthi ≤ 1,000), the two intersections the trail connects, and they know that no two intersections are directly connected by two different trails. The trails form a structure known mathematically as a graph.
To run the relay, the N cows position themselves at various intersections (some intersections might have more than one cow). They must position themselves properly so that they can hand off the baton cow-by-cow and end up at the proper finishing place.
Write a program to help position the cows. Find the shortest path that connects the starting intersection (S) and the ending intersection (E) and traverses exactly N cow trails.
给出一张无向连通图,求S到E经过k条边的最短路。
Input
-
Line 1: Four space-separated integers: N, T, S, and E
- Lines 2..T+1: Line i+1 describes trail i with three space-separated integers: lengthi , I1i , and I2i
Output
- Line 1: A single integer that is the shortest distance from intersection S to intersection E that traverses exactly N cow trails.
Sample Input
2 6 6 4
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9
Sample Output
10
题解
解法一:
考虑有用的点数很少,我们可以哈希一下,建立邻接矩阵,矩阵加速求出经过$N$条边的从$S$到$T$的最短路。
1 #include<set> 2 #include<map> 3 #include<stack> 4 #include<ctime> 5 #include<cmath> 6 #include<queue> 7 #include<string> 8 #include<cstdio> 9 #include<vector> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 #define LL long long 15 #define RE register 16 #define IL inline 17 using namespace std; 18 const int INF=1e9; 19 20 IL int Min(int a,int b){return a<b ? a:b;} 21 22 int num[1005],pos; 23 int f[205][205]; 24 int k,m,s,e,u,v,l; 25 struct mat 26 { 27 int a[205][205]; 28 mat() {for (int i=1;i<=pos;i++)for (int j=1;j<=pos;j++) a[i][j]=INF;} 29 mat operator * (const mat &b) 30 { 31 mat ans; 32 for (RE int i=1;i<=pos;i++) 33 for (RE int j=1;j<=pos;j++) 34 for (RE int k=1;k<=pos;k++) 35 ans.a[i][j]=Min(ans.a[i][j],a[i][k]+b.a[k][j]); 36 return ans; 37 } 38 }; 39 40 int main() 41 { 42 scanf("%d%d%d%d",&k,&m,&s,&e); 43 for (RE int i=1;i<=m;i++) 44 { 45 scanf("%d%d%d",&l,&u,&v); 46 if (!num[u]) num[u]=++pos; 47 if (!num[v]) num[v]=++pos; 48 f[num[u]][num[v]]=f[num[v]][num[u]]=l; 49 } 50 mat S,T; 51 for (RE int i=1;i<=pos;i++) for (RE int j=1;j<=pos;j++) if (f[i][j]) S.a[i][j]=T.a[i][j]=f[i][j]; 52 k--; 53 while (k) 54 { 55 if (k&1) S=S*T; 56 k>>=1; 57 T=T*T; 58 } 59 printf("%d\n",S.a[num[s]][num[e]]); 60 return 0; 61 }
解法二:
利用倍增的思想。令$f[i][j][t]$表示从$i$到$j$经过$2^t$条边的最优值,做一遍$floyd$再统计答案即可。
1 #include<cmath> 2 #include<queue> 3 #include<ctime> 4 #include<stack> 5 #include<cstdio> 6 #include<string> 7 #include<cstdlib> 8 #include<cstring> 9 #include<iostream> 10 #include<algorithm> 11 using namespace std; 12 const int INF=1e9; 13 14 int num[1005],pos; 15 int f[205][205][25]; 16 int towards[205][2]; 17 bool t; 18 int k,m,s,e,u,v,l; 19 20 int main() 21 { 22 memset(f,127/3,sizeof(f)); 23 memset(towards,127/3,sizeof(towards)); 24 scanf("%d%d%d%d",&k,&m,&s,&e); 25 for (int i=1;i<=m;i++) 26 { 27 scanf("%d%d%d",&l,&u,&v); 28 if (!num[u]) num[u]=++pos; 29 if (!num[v]) num[v]=++pos; 30 f[num[u]][num[v]][0]=f[num[v]][num[u]][0]=l; 31 } 32 int lim=log2(k); 33 for (int p=1;p<=lim;p++) 34 for (int q=1;q<=pos;q++) 35 for (int i=1;i<=pos;i++) 36 for (int j=1;j<=pos;j++)// if (i!=j&&q!=i) 37 if (f[i][j][p]>f[i][q][p-1]+f[q][j][p-1]) 38 f[i][j][p]=f[i][q][p-1]+f[q][j][p-1]; 39 int p=0; 40 towards[num[s]][t]=0; 41 while (k!=0) 42 { 43 if (k&1) 44 { 45 t=!t; 46 for (int i=1;i<=pos;i++) 47 { 48 towards[i][t]=INF; 49 for (int j=1;j<=pos;j++) 50 if (towards[i][t]>towards[j][!t]+f[i][j][p]) 51 towards[i][t]=towards[j][!t]+f[i][j][p]; 52 } 53 } 54 p++; 55 k=k>>1; 56 } 57 printf("%d\n",towards[num[e]][t]); 58 return 0; 59 }