[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 }
倍增
posted @ 2017-08-15 14:28  NaVi_Awson  阅读(342)  评论(0编辑  收藏  举报