relays 奶牛接力跑(矩阵快速幂求最短路径)

题干:

  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条跑道。

题解:

  看到 n 这么大吓了一跳,最后看到 n 其实就是路径长度,基本上这就是矩阵快速幂了。但是节点大小为1~1000,显然难以承受,但是它的边不过 100 条,所以它有用的点最多为 101 个(连通),通过离散化可以实现(或者先建边,dfs一遍标个号即可)。将路径长度作为指数,直接将每个边的长度作为矩阵的值进行矩阵快速幂。

  为什么要将将每个边的长度直接作为矩阵的值?不用缩点吗?若我们进行缩点,100000 个点一定无法接受。再者,其实若是求必经 n 条路的最短路径长度,我们矩阵的定义就变为了由 x 到 y 节点必须经过 z 条路径的最小值,而每个节点的值就是路径长度,所以不需缩点。

  但是如果是普通的矩阵快速幂,它求出的只是经过一个点的路径种类数,无法满足我们的预期,我们可以将矩阵乘法由题意改变一下,变为:

sum.a[i][j]=min(sum.a[i][j],aa.a[i][k]+bb.a[k][j]);

  可以发现,把矩阵乘法的∑改成取 min 一样满足分配律,所以我们是可以将矩阵乘法变为我们所需要的形式。

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define $ 111
 5 using namespace std;
 6 int m,n,t,start,done,in[$],sta[$*2],out[$],w[$],up;
 7 inline int min(int x,int y){    return x<y?x:y;    }
 8 struct tree{
 9     int a[$][$];
10     tree(){    memset(a,63,sizeof(a));    }
11     friend tree operator * (tree aa,tree bb){
12         tree sum=tree();
13         for(register int k=1;k<=m;++k)
14             for(register int i=1;i<=m;++i)
15                 for(register int j=1;j<=m;++j)
16                     sum.a[i][j]=min(sum.a[i][j],aa.a[i][k]+bb.a[k][j]);
17         return sum;
18     }
19     friend tree operator ^ (tree aa,int x){
20         tree sum=tree();
21         for(register int i=1;i<=m;++i) sum.a[i][i]=0;
22         for(;x;x>>=1,aa=aa*aa) if(x&1) sum=sum*aa;
23         return sum;
24     }
25 };
26 signed main(){
27     tree ans=tree();
28     scanf("%d%d%d%d",&n,&t,&start,&done);
29     for(register int i=1;i<=t;++i)
30         scanf("%d%d%d",&w[i],&in[i],&out[i]),sta[++up]=in[i],sta[++up]=out[i];
31     sta[++up]=start, sta[++up]=done;
32     sort(sta+1,sta+up+1);
33     m=unique(sta+1,sta+up+1)-sta-1;
34     for(register int i=1;i<=t;++i){
35         in[i]=lower_bound(sta+1,sta+m+1,in[i])-sta;
36         out[i]=lower_bound(sta+1,sta+m+1,out[i])-sta;
37         ans.a[in[i]][out[i]]=ans.a[out[i]][in[i]]=w[i];
38     }
39     start=lower_bound(sta+1,sta+m+1,start)-sta;
40     done= lower_bound(sta+1,sta+m+1,done)-sta;
41     ans=ans^n;
42     printf("%d\n",ans.a[start][done]);
43 }

原文地址:https://www.cnblogs.com/OI-zzyy/p/11202571.html

时间: 2024-10-18 11:35:05

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】【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

[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)条跑道上. 农场上的跑道有一些交汇点,每条跑道都连结

POJ 3070-Fibonacci(矩阵快速幂求斐波那契数列)

Fibonacci Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3070 Appoint description:  System Crawler  (2015-02-28) Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn ? 1 +

poj 3070 Fibonacci (矩阵快速幂求斐波那契数列的第n项)

题意就是用矩阵乘法来求斐波那契数列的第n项的后四位数.如果后四位全为0,则输出0,否则 输出后四位去掉前导0,也...就...是...说...输出Fn%10000. 题目说的如此清楚..我居然还在%和/来找后四位还判断是不是全为0还输出时判断是否为0然后 去掉前导0.o(╯□╰)o 还有矩阵快速幂的幂是0时要特判. P.S:今天下午就想好今天学一下矩阵乘法方面的知识,这题是我的第一道正式接触矩阵乘法的题,欧耶! #include<cstdio> #include<iostream>

hdu 3221 Brute-force Algorithm(快速幂取模,矩阵快速幂求fib)

http://acm.hdu.edu.cn/showproblem.php?pid=3221 一晚上搞出来这么一道题..Mark. 给出这么一个程序,问funny函数调用了多少次. 我们定义数组为所求:f[1] = a,f[2] = b, f[3] = f[2]*f[3]......f[n] = f[n-1]*f[n-2].对应的值表示也可为a^1*b^0%p,a^0*b^1%p,a^1*b^1%p,.....a^fib[n-3]*b^fib[n-2]%p.即a,b的指数从n=3以后与fib数列

【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 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

poj 3070 Fibonacci 【矩阵快速幂 求第N个斐波那契数%1000】

Fibonacci Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11123   Accepted: 7913 Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn ? 1 + Fn ? 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequenc