1. 程式人生 > >2017-10-7 vijos 無向圖最短路徑

2017-10-7 vijos 無向圖最短路徑

描述

無向圖最短路徑問題,是圖論中最經典也是最基礎的問題之一。本題我們考慮一個有 nn 個結點的無向圖 GG。
GG 是簡單完全圖,也就是說 GG 中沒有自環,也沒有重邊,但任意兩個不同的結點之間都有一條帶權的雙向邊。
每一條邊的邊權是非負實數,但我們並不知道每一條邊的具體邊權。
好訊息是我們知道 GG 中任意兩點最短路徑的長度d(i,j)d(i,j)。且保證至少有一種邊權的分配方案滿足得到的帶權圖中ii與jj的最短路長度恰好是d(i,j)d(i,j)。
下面是留給你的任務:對於任意一對點(i,j)(i,j),希望你能找出來所有合法的邊權分配方案中ii和jj之間邊權的最大值。
格式

輸入格式

本題中,每一組資料都有多次詢問,每一次詢問分別給出了一個無向圖GG。
輸入的第一行是一個整數 tt,表示總共的詢問個數。之後依次給出每一次詢問。
對於每一次詢問來說,第一行給出了 G 中結點總數 n。之後n行每行有n個整數,給出了一個n×n的矩陣 d,其中第ii行第jj列的整數對應 d(i,j)d(i,j)表示ii到jj的最短路徑長度。
因為圖GG是簡單無向圖,對角線元素d(i,i)d(i,i)總是0,且矩形是對稱的(也就是說d(i,j)=d(j,i)d(i,j)=d(j,i))。
輸出格式

對於每一次詢問,若給定的圖GG有nn個結點,則輸出nn行,每行有nn個整數,描述了一個矩陣 aa。矩陣的第ii行第jj列表示連線ii和jj的邊的最大可能邊權。如果(i,j)(i,j)的邊權可以任意大,則輸出字串infty表示無限。
矩陣的對角線沒有實質性意義,請全輸出00。因為GG是無向圖,所以輸出的矩陣aa應該也是對稱的(即a(i,j)=a(j,i)a(i,j)=a(j,i))。
不難發現,因為給定的矩陣 dd 中每一個數字都是整數,所以最大可能邊權總會是整數。
樣例1

樣例輸入1

2
3
0 2 8
2 0 10
8 10 0
3
0 1 1
1 0 1
1 1 0

樣例輸出1

0 2 8
2 0 infty
8 infty 0
0 1 1
1 0 1
1 1 0

限制

對於 20\%20% 的資料,有 n = 3n=3。
對於 50\%50% 的資料,有 1≤n≤10。
對於 100\%100% 的資料,有 1≤n≤100,且所有詢問中nn的和不超過 800800,對於所有的dd滿足1≤d≤256。
每一組資料的時限為 0.5 秒。

題解
這個題挺有意思。
題目大意:給出的是所有兩點間的最短路徑,要求出圖中兩點的可能的最大邊權,不會對最短路產生影響。
怎麼考慮這個問題呢?首先我們把給出的最短路暫定為兩條邊之間的邊權,然後跑floyed,要求是不能只經過一條路到達(即把兩點間的最短路抹掉),如果這樣得出的兩點間的最短路於原來的最短路相等,那麼直接連線這兩個點的邊可以任意大,否則就不變。
怎麼能讓他不能一條邊到達呢?重新開一個數組記錄。

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int T,n,d[101][101],m[101][101];

int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        for (int i=1; i<=n; i++)
            for (int j=1; j<=n; j++)
                scanf("%d",&d[i][j]);
//      for (int i=1; i<=n; i++) m[i][i]=0x7fffffff;
        memset(m,0x7f,sizeof(m));
        for (int k=1; k<=n; k++)
            for (int i=1; i<=n; i++)
                for (int j=1; j<=n; j++)
                if (i!=j&&j!=k&&i!=k)
                    m[i][j]=min(m[i][j],d[i][k]+d[k][j]);
        for (int i=1; i<=n; i++)
            for (int j=1; j<=n; j++)
            {
                if (m[i][j]==d[i][j]&&i!=j) d[i][j]=-1;
            }
        for (int i=1; i<=n; i++)
        {
            for (int j=1; j<=n; j++)
                if (d[i][j]==-1) printf("infty ");//==和=
                else printf("%d ",d[i][j]);
            printf("\n");
        }
    }
    return 0;
}

對noip來說,可能不需要那麼多的演算法。需要做到的是如何獨立的思考問題,並將自己的想法轉化成程式碼。同時還要做到認真,細緻。