NKOJ 1895 奶牛接力赛
时间限制 : 10000 MS 空间限制 : 65536 KB
问题描述
为了锻炼身体,N(2 ≤ N ≤ 1,000,000)只奶牛决定用牧场里的T (2 ≤ T ≤ 100)条小路进行一场跑步接力赛。
每条小路连接两个不同的交点(1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000),每个交点至少连接两条小路。奶牛们知道每条小路的长度(1<=长度<=1,000),两个交点间最多只有一条小路直接相连。
为了完成接力赛,赛前这N头奶牛可以把自己安置在任意交点上(每个交点上可以安排多只奶牛)。但是奶牛们必须把自己安置在恰当的位置上,这样才能一个接一个地把接力棒传到指定的终点。
请写一个程序帮助奶牛们找到合适的位置。请找出从起点(S)到终点(E)的恰好经过了N头奶牛的最短路径。
输入格式
第一行,4个空格间隔的整数N,T,S,E
接下来T行,每行3个空格间隔的整数,z,x,y表示交点x和y之间有条长度为z的小路直接相连。
输出格式
一个整数,表示从起点S到终点E的恰好经过了N头奶牛的最短路的长度。
样例输入
2 6 6 4
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9
样例输出
10
来源 USACO
思路:
1、考虑Floyd思想将矩阵乘法替换为Floyd,用以求最短路径
2、多次Floyd仍用蒙哥马利优化。
3、其他:
因为路的数量不超过100所以点的数量不会超过100,而题目所给点编号范围为1000,所以需要压缩。并能减少Floyd时间复杂度。
ans数组初值中点到自己距离为0,到其他点距离为inf。可理解为ans&a后a不变
c数组初值全为inf。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int inf=1e9;
const int need=103;
typedef int int_[need][need];
int_ ans,a,c;
int n,t,x,y,m=0,belong[1000];
void floyd(int_ a,int_ b)
{
for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) c[i][j]=inf;
for(int k=1;k<=m;k++)
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
c[i][j]=min(c[i][j],a[i][k]+b[k][j]);
for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) a[i][j]=c[i][j];
}
void solve(int b)
{
for(int i=1;i<=m;i++) ans[i][i]=0;
while(b)
{
if(b&1) floyd(ans,a);
b>>=1;
floyd(a,a);
}
}
int main()
{
scanf("%d%d%d%d",&n,&t,&x,&y);
for(int i=1,p,q,z;i<=t;i++)
{
scanf("%d%d%d",&z,&p,&q);
if(belong[p]==0) belong[p]=++m;
if(belong[q]==0) belong[q]=++m;
a[belong[p]][belong[q]]=a[belong[q]][belong[p]]=z;
}
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
{
if(a[i][j]==0) a[i][j]=inf;
ans[i][j]=inf;
}
solve(n);
printf("%d",ans[belong[x]][belong[y]]);
}