[BZOJ] 1706: [usaco2007 Nov]relays 奶牛接力跑
Posted Lev今天学习了吗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ] 1706: [usaco2007 Nov]relays 奶牛接力跑相关的知识,希望对你有一定的参考价值。
1706: [usaco2007 Nov]relays 奶牛接力跑
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 707 Solved: 367
[Submit][Status][Discuss]
Description
FJ的N(2 <= N <= 1,000,000)头奶牛选择了接力跑作为她们的日常锻炼项目。至于进行接力跑的地点 自然是在牧场中现有的T(2 <= T <= 100)条跑道上。 农场上的跑道有一些交汇点,每条跑道都连结了两个不同的交汇点 I1_i和I2_i(1 <= I1_i <= 1,000; 1 <= I2_i <= 1,000)。每个交汇点都是至少两条跑道的端点。 奶牛们知道每条跑道的长度length_i(1 <= length_i <= 1,000),以及每条跑道连结的交汇点的编号 并且,没有哪两个交汇点由两条不同的跑道直接相连。你可以认为这些交汇点和跑道构成了一张图。 为了完成一场接力跑,所有N头奶牛在跑步开始之前都要站在某个交汇点上(有些交汇点上可能站着不只1头奶牛)。当然,她们的站位要保证她们能够将接力棒顺次传递,并且最后持棒的奶牛要停在预设的终点。 你的任务是,写一个程序,计算在接力跑的起点(S)和终点(E)确定的情况下,奶牛们跑步路径可能的最小总长度。显然,这条路径必须恰好经过N条跑道。
Input
* 第1行: 4个用空格隔开的整数:N,T,S,以及E
* 第2..T+1行: 第i+1为3个以空格隔开的整数:length_i,I1_i,以及I2_i, 描述了第i条跑道。
Output
* 第1行: 输出1个正整数,表示起点为S、终点为E,并且恰好经过N条跑道的路 径的最小长度
Sample Input
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9
Sample Output
HINT
Source
Analysis
分步Floyd qwq
我今儿算是学到了新套路了...
首先复习一波Floyd原理
三层循环 k i j
表示 i -> j 的路径中插入 k ,如果路径更短的话就更新为 i -> k -> j
所以根据这个
我们知道:整个邻接矩阵更新几次,就是所有的最短路径里有几条边
(如果不更新的话,那么所有路径都只有一条边,也就是初始矩阵)
那么把这个写成一个矩阵间的二元运算关系,A @ B = C
在这个过程中,C[ i ][ j ] = min(C[ i ][ j ],A[ i ][ k ]+B[ k ][ j ])
和Floyd是一样的
这东西,还符合结合律
所以对于 k 步Floyd 我们可以写成一个矩阵快速幂,只是运算从矩阵相乘变成了这个单步Floyd
那么对于这道题
其实就是求 n 步Floyd之后起点和终点之间的距离
那么一个离散化(因为数据范围有点诡异)+ 一个分步Floyd求终矩阵
比较简单,没有其他坑点
Code
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 6 const int inf = 1e9; 7 int Poi = 1,poi,Chart[300],chart[3000000],s,t,n,k,a,b,c; 8 9 struct MAT{ 10 int mat[300][300]; 11 MAT(){ 12 for(int i = 1;i < 300;i++) 13 for(int j = 1;j < 300;j++) 14 mat[i][j] = inf; 15 } 16 17 void print(){cout << endl; 18 for(int i = 1;i <= n;i++){ 19 for(int j = 1;j <= n;j++) 20 cout << mat[i][j] << ‘ ‘; 21 cout << endl; 22 } 23 } 24 }S; 25 26 struct list{ 27 int a,b,c; 28 }arr[300]; 29 30 int find(int x){ 31 int L = 1,R = Poi-1,mid; 32 while(L < R){ 33 mid = (L+R)/2; 34 if(Chart[mid] < x) L = mid+1; 35 else R = mid; 36 }return L; 37 } 38 39 void Init(){ 40 sort(chart,chart+poi); 41 Chart[Poi++] = chart[0]; 42 Poi = 1; 43 for(int i = 1;i < poi;i++) 44 if(chart[i] != Chart[Poi-1]) Chart[Poi++] = chart[i]; 45 s = find(s); 46 t = find(t); 47 for(int i = 1;i <= n;i++){ 48 int aa,bb; 49 aa = find(arr[i].a),bb = find(arr[i].b),c = arr[i].c; 50 // printf("%d %d %d\n",aa,bb,c); 51 S.mat[aa][bb] = S.mat[bb][aa] = c; 52 }n = Poi-1; 53 } 54 55 MAT mul(MAT A,MAT B){ 56 MAT C; 57 for(int k = 1;k <= n;k++) 58 for(int i = 1;i <= n;i++) 59 for(int j = 1;j <= n;j++) 60 C.mat[i][j] = min(C.mat[i][j],A.mat[i][k]+B.mat[k][j]); 61 return C; 62 } 63 64 MAT ksm(MAT A,int kk){ 65 // printf("BFYAYIYE"); 66 MAT B = A; kk--; 67 // if(!kk) return A; 显然这行代码没有任何问题,但是加入后这个RE了,求大佬解释啊qwq 68 69 70 while(kk){ 71 // B.print(); 72 if(kk&1) B = mul(B,A); 73 A = mul(A,A); 74 kk >>= 1; 75 }return B; 76 } 77 78 int main(){ 79 freopen("LLQ.in","r",stdin); 80 // freopen("LLQ.out","w",stdout); 81 82 scanf("%d%d%d%d",&k,&n,&s,&t); 83 84 for(int i = 1;i <= n;i++){ 85 scanf("%d%d%d",&c,&a,&b); 86 arr[i].a = a; 87 arr[i].b = b; 88 arr[i].c = c; 89 // chart[poi++] = a; 90 chart[poi++] = a; 91 chart[poi++] = b; 92 } 93 94 Init(); 95 96 // for(int i = 0;i <= Poi;i++) cout << Chart[i] << ‘ ‘; 97 98 // S.print(); 99 S = ksm(S,k); 100 101 printf("%d",S.mat[s][t]); 102 103 return 0; 104 }
以上是关于[BZOJ] 1706: [usaco2007 Nov]relays 奶牛接力跑的主要内容,如果未能解决你的问题,请参考以下文章
bzoj1706: [Usaco2007 Nov]relays 奶牛接力跑 (Floyd+新姿势)
[bzoj1706] [usaco2007 Nov]relays 奶牛接力跑
bzoj1706/usaco2007 Novrelays 奶牛接力跑——矩阵快速幂/倍增floyd
Floyd矩阵乘法BZOJ1706- [usaco2007 Nov]relays 奶牛接力跑