[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

时间: 2024-10-11 07:34:40

[BZOJ] 1706: [usaco2007 Nov]relays 奶牛接力跑的相关文章

矩阵乘法专题2——bzoj 1706 [usaco2007 Nov] relays 奶牛接力跑 题解

转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24960651 [原题] 1706: [usaco2007 Nov]relays 奶牛接力跑 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 340  Solved: 162 [Submit][Status] Description FJ的N(2 <= N <= 1,000,000)头奶牛选择了接力跑作为她们的日常锻炼项目.至于进行接力

BZOJ 1706 usaco2007 Nov relays 奶牛接力跑 倍增Floyd

题目大意:给定一张无向图,求从s出发恰好经过n条边到达e的最短路 倍增Floyd--为何大家都管这个叫做矩阵乘法- - 算了为何要纠结这种事- - 令f[p][i][j]表示走2^p步从i到达j的最短路 有f[p][i][j]=min{f[p-1][i][k]+f[p-1][k][j]} 将n进行二进制拆分 用矩阵g记录答案矩阵 对于每一位p 用f[p]和g两个矩阵搞出h 再将h的值赋给g 切忌直接用f[p]更新g 这样可能导致g的上一次的值被继承到下一次里 这样相当于这一步没跑 100条边,因

bzoj 1706: [usaco2007 Nov]relays 奶牛接力跑【矩阵乘法+Floyd】

唔不知道怎么说--大概核心是把矩阵快速幂的乘法部分变成了Floyd一样的东西,非常之神 首先把点离散一下,最多有200个,然后建立邻接矩阵,a[u][v]为(u,v)之间的距离,没路就是inf 然后注意重载乘号的部分,注意到这样乘一次就相当于把本来存了经过k条路的最短路的邻接矩阵变成存了经过k+1条路的最短路的邻接矩阵 这样看来乘n次就行了,这里用矩阵快速幂 妙啊 #include<iostream> #include<cstdio> using namespace std; co

bzoj1706: [Usaco2007 Nov]relays 奶牛接力跑 (Floyd+新姿势)

题目大意:有t(t<=100)条无向边连接两点,求s到e刚好经过n(n<=10^7)条路径的最小距离. 第一反应分层图,但是一看n就懵逼了,不会写.看了题解之后才知道可以这么玩... 首先有100条边最多200个点,但点编号到1000,所以离散化一下. 任何一个正整数都能用2的幂相加得到,所以先把n转变成2进制来看,按位考虑.dist[i][j][k]表示刚好经过2^i条边从j到k的最短距离,则dist[i,j,k]=min{dist[i-1][j][l]+dist[i-1][l][k]}.用

[bzoj1706] [usaco2007 Nov]relays 奶牛接力跑

大概是叫倍增Floyd? 显然最多200个点...f[i][j][k]表示从j到k,走2^i步的最小路程.就随便转移了.. 查询的话就是把n二进制位上是1的那些都并起来. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cstdlib> 6 #define ll long long 7 #define ull

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

矩阵乘法(快速幂) 为说明方便,这里让\(k\)为点数,\(n\)为路径长度. 先将点都离散化,这样最后的点只有\(2k\)个. 先考虑一种暴力,每次用\(O(k^3)\)的复杂度来暴力更新,设当前长度\(l\)点的两两最短路矩阵为\(S\),现在要转移到\(l+1\)时的最短路矩阵\(T\).我们考虑用每条边更新,对于某条从\(x\)连向\(y\)的长度为\(z\)的边,对于任一点\(i\),有: \[T[i][y]=min(T[i][y],T[i][x]+z)\] 另外,每次更新时,\(T\

BZOJ 1706 usaco 2007 Nov relays 奶牛接力跑/POJ 3613 Cow Relays 倍增Floyd

题目大意:求恰好走k步从S到T的最短路. 思路:设f[p][i][j]为从i到j恰好走2^p步的最短路,DP方程十分简单:f[p][i][j] = min(f[p][i][j],f[p - 1][i][k] + f[p - 1][k][j]); 对总步数T进行二进制拆分,在T有1的位置上,假如这个位置为p,那么就用f[p][][]来更新答案g[][],最后得到的g[][]就是答案矩阵. 注意要离散化一下.. CODE: #include <cstdio> #include <cstrin

【Floyd矩阵乘法】BZOJ1706- [usaco2007 Nov]relays 奶牛接力跑

[题目大意] 给出一张无向图,求出恰巧经过n条边的最短路. [思路] 首先题目中只有100条边,却给出了10000个点(实际上最多只能有200个),离散化一下. 后面就是Floyd的新姿势,以前看过的集训队论文里面有:D 一开始的邻接矩阵是经过一条边的最短路,把这个邻接矩阵记作f[0] f[1]=f[0]*f[0]=f[0]^2(这里的乘法是矩阵乘法),就可以表示恰巧经过两条边的啦. f[2]=f[1]*f[0]=f[0]^3,恰巧表示经过两条边. -- 所以恰巧经过n条边的最短路是f[n-1]

【BZOJ】【1046】/【POJ】【3613】【USACO 2007 Nov】Cow Relays 奶牛接力跑

倍增+Floyd 题解:http://www.cnblogs.com/lmnx/archive/2012/05/03/2481217.html 神题啊= =Floyd真是博大精深…… 题目大意为求S到E,恰好经过N条边的最短路径(姑且称为路径吧,虽然好像已经不是了……) 总共只有大约200个点(很多点根本没走到,离散化一下即可)所以可以考虑Floyd算最短路. 引用下题解: 题目求i,j之间边数恰为N的最短路径(边可以重复走),我们知道线性代数中有:01邻接矩阵A的K次方C=A^K,C[i][j