[BZOJ] 1706: [usaco2007 Nov]relays 奶牛接力跑

1706: [usaco2007 Nov]relays 奶牛接力跑

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 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

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

HINT

 

Source

Gold

 

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 }
分步Floyd

 

posted @ 2017-09-24 22:15  Leviaton  阅读(221)  评论(0编辑  收藏  举报