POJ 3613 Cow Relays

来源:互联网 发布:上海迪士尼游客数据 编辑:程序博客网 时间:2024/05/29 18:21

大概是倍增Floyd的模板题。

Floyd的原理是一个一个点向图中加,k表示已经加了k个点,并且加点可以累加。(可以参考上篇博文)而这道题恰是强制加入T个点,那么我们可以将T利用一种类似于加速幂的思想向其中加点。而需要注意的是,两个数组的合并需要第三个辅助数组维护,辅助数组初值应设为无限大,用已知的两个数组去更新辅助数组,最后将辅助数组中的值赋给答案数组。
还需要注意,答案数组一开始除了自己到自己,其他的全赋为无限大,因为代价为0时每个节点可以到达的地方仅为其本身。

其实这道题本身可以用矩阵来理解,矩阵具有结合律,本题的一种路径相加也满足结合律,将矩阵乘法的定义改为取min即可(大概也是理解倍增Floyd的一种思路)。

#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<algorithm>using namespace std;const int maxn=205;struct edge{    int x,y,val;}e[maxn];int n,cnt;int disc[maxn<<3],map[maxn][maxn],dist[maxn][maxn],temp[maxn][maxn];void floyd(int a[][maxn],int b[][maxn]){    memset(temp,0x3f,sizeof temp);//合并两种状态,必须赋初值以最大值     for(int k=1;k<=n;k++)        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                temp[i][j]=min(temp[i][j],a[i][k]+b[k][j]);    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            a[i][j]=temp[i][j];}int main(){    int k,m,S,T;z    scanf("%d%d%d%d",&k,&m,&S,&T);    memset(map,0x3f,sizeof map);    memset(dist,0x3f,sizeof dist);    for(int i=1,u,v,val;i<=m;i++)    {        scanf("%d%d%d",&val,&u,&v);        e[i].x=u;e[i].y=v;e[i].val=val;        disc[++cnt]=u;disc[++cnt]=v;    }    sort(disc+1,disc+cnt+1);    n=unique(disc+1,disc+cnt+1)-(disc+1);    S=lower_bound(disc+1,disc+n+1,S)-disc;    T=lower_bound(disc+1,disc+n+1,T)-disc;    //路径为0时花费均为0,所以初始状态自身到自身dist不赋值     for(int i=1;i<=n;i++)dist[i][i]=0;    for(int i=1;i<=m;i++)    {        int x=lower_bound(disc+1,disc+n+1,e[i].x)-disc;        int y=lower_bound(disc+1,disc+n+1,e[i].y)-disc;        map[x][y]=map[y][x]=e[i].val;    }    while(k)    {        if(k&1)floyd(dist,map);        floyd(map,map);        k>>=1;    }    printf("%d",dist[S][T]);    return 0;}
原创粉丝点击