poj 3613 Cow Relays

题目大意:
Input

  • Line 1: Four space-separated integers: N, T, S, and E
  • Lines 2..T+1: Line i+1 describes trail i with three space-separated integers: lengthi , I1i , and I2i

Output

  • Line 1: A single integer that is the shortest distance from intersection S to intersection E that traverses exactly N cow trails.

Sample Input

2 6 6 4——–n个点,t条边,起点s,终点e
11 4 6——–4到6有一条权值为11的边
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9
Sample Output

10
求一条从s到e的经过n条边的最短路
用矩阵乘法+快速幂的思想。
A(i,j)=1代表从i到j有1条边
A(i,j)*A(i,j)=∑A(i,k)*A(k,j)
(当A(i,k)和A(k,j)都为1是才有意义)
那么A的平方代表从i到j有一条经过k的边,也就是路径为2
那么A的(k-1)次方代表路径为k
于是我们定义新的矩阵乘法
把相乘的部分改为Floyd
但是枚举k次方可能会TLE,所以用快速幂(*快速幂详见–模板–快速幂)

#include<algorithm>//floyd是通过枚举k来更新dis(i,j)所以只要枚举n-1次k就可以求得经过n条边的最短路 
#include<iostream>
#include<cstring>
#include<cstdio> 
#include<cmath>
using namespace std;
int n,t,s,e;//n头牛,t条边,起点s终点e 
int f[30+10][200+10][200+10],ll;
int a[1000+10],cnt,b[200+10][200+10],ans[200+10][200+10];//a数组记录i点的映射 
void pow(){ //快速幂 
    ll=0;
    while(n>0){
        if(n%2==1){//如果是奇数----ans=(ans*a)%c 
            memset(b,0x3f,sizeof(b));
//          for(int i=0;i<=cnt;i++)********此处一定不能初始化对角线元素,因为对角线元素已经改变 
//              b[i][i]=0;
            for(int k=1;k<=cnt;k++)
                for(int i=1;i<=cnt;i++)
                    for(int j=1;j<=cnt;j++)
                        b[i][j]=min(b[i][j],min(ans[i][k]+f[ll][k][j],f[ll][i][k]+ans[k][j])); 
            for(int i=1;i<=cnt;i++)
                for(int j=1;j<=cnt;j++)
                    ans[i][j]=b[i][j];
        }
        //a=a*a%c
        ll++;
        for(int k=1;k<=cnt;k++)
            for(int i=1;i<=cnt;i++)
                for(int j=1;j<=cnt;j++)
                    f[ll][i][j]=min(f[ll-1][i][k]+f[ll-1][k][j],f[ll][i][j]);
        n>>=1;  
    }
}
int main(){
    cnt=0;
    memset(a,0,sizeof(a));//如果a[i]为0代表i没有映射 
    scanf("%d%d%d%d",&n,&t,&s,&e);
    memset(ans,0x3f,sizeof(ans));
    memset(f,0x3f,sizeof(f));
//  for(int i=0;i<=210;i++)
//      f[0][i][i]=0;********此处不能初始化对角线元素,有自环
    for(int i=1;i<=200;i++)
        ans[i][i]=0;
    for(int i=1,x,y,z;i<=t;i++){
        scanf("%d%d%d",&z,&x,&y);
        if(!a[x])
            a[x]=++cnt;
        if(!a[y])
            a[y]=++cnt;
        if(f[0][a[x]][a[y]]>z){//有重边 
            f[0][a[x]][a[y]]=z;//无向边
            f[0][a[y]][a[x]]=z;     
        }
    }
    pow();
    cout<<ans[a[s]][a[e]]<<endl;
    return 0;
}
/*
100 6 6 4
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值