POJ 3613 Cow Relays - 倍增Floyd(矩陣加速冪)

大概是倍增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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章