AcWing 345. 牛站

原题链接

考察:Floyd+矩阵快速幂

思路:

        前面讲过Floyd算法的第一层循环是i~j的最短路,经过1~k的结点.在这里我们将Floyd的dp状态表示f[k,i,j].

        假设i经过a条边到达S, f[k,i,j] = f[a,i,S]+f[k-a,S,j]  我们可以发现前a条边的路径与后面的路径不相干,所以我们可以这么写.

        然后就可以发现k可以被分成1条,2条,4条...符合结合律我们可以用矩阵快速幂.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <map>
 4 using namespace std;
 5 const int N = 1010,M = 210;
 6 map<int,int> mp;
 7 int n,T,S,E,idx,g[M][M],res[M][M],tmp[M][M];
 8 int get(int x)
 9 {
10     if(!mp.count(x)) mp[x] = ++idx;
11     return mp[x];
12 }
13 void mul(int res[][M],int g[][M])
14 {
15     memset(tmp,0x3f,sizeof tmp);
16     for(int k=1;k<=idx;k++)
17       for(int i=1;i<=idx;i++)
18         for(int j=1;j<=idx;j++)
19           tmp[i][j] = min(res[i][k]+g[k][j],tmp[i][j]);
20     memcpy(res,tmp,sizeof tmp);
21 }
22 void mulself(int g[][M])
23 {
24     memset(tmp,0x3f,sizeof tmp);
25     for(int k=1;k<=idx;k++)
26       for(int i=1;i<=idx;i++)
27         for(int j=1;j<=idx;j++)
28           tmp[i][j] = min(g[i][k]+g[k][j],tmp[i][j]);
29     memcpy(g,tmp,sizeof tmp);
30 }
31 int main()
32 {
33     scanf("%d%d%d%d",&n,&T,&S,&E);
34     memset(g,0x3f,sizeof g); memset(res,0x3f,sizeof res);
35     while(T--)
36     {
37         int a,b,w; scanf("%d%d%d",&w,&a,&b);
38         int pa = get(a),pb =get(b);
39         g[pa][pb] = g[pb][pa] = min(g[pb][pa],w);
40     }
41     S = get(S),E = get(E);
42     for(int i=1;i<=idx;i++) res[i][i] = 0;
43     memcpy(res,g,sizeof g);
44     n--;
45     while(n)
46     {
47         if(n&1) mul(res,g);
48         mulself(g);
49         n>>=1;
50     }
51     printf("%d\n",res[S][E]);
52     return 0;
53 }

 

上一篇:html实现01代码雨(转载)(附带运行方法)


下一篇:新发现——同花顺数