1. 程式人生 > >Vijos - 社交網路(Floyd擴充套件)

Vijos - 社交網路(Floyd擴充套件)

題目連結:https://vijos.org/p/1591

題目描述

在社交網路(social network)的研究中,我們常常使用圖論概念去解釋一些社會現象。
不妨看這樣的一個問題。在一個社交圈子裡有n個人,人與人之間有不同程度的關係。我們將這個關係網路對應到一個n個結點的無向圖上,兩個不同的人若互相認識,則在他們對應的結點之間連線一條無向邊,並附上一個正數權值c,c越小,表示兩個人之間的關係越密切。
我們可以用對應結點之間的最短路長度來衡量兩個人s和t之間的關係密切程度,注意到最短路徑上的其他結點為s和t的聯絡提供了某種便利,即這些結點對於s和t之間的聯絡有一定的重要程度。我們可以通過統計經過一個結點v的最短路徑的數目來衡量該結點在社交網路中的重要程度。
考慮到兩個結點A 和B 之間可能會有多條最短路徑。我們修改重要程度的定義如下:
令Cs,t 表示從s 到t 的不同的最短路的數目,Cs,t(v)表示經過v從s到t的最短路的數目;則定義
I(v)=∑(s<>v,t<>v)Cs,t(v)/Cs,t
為結點v 在社交網路中的重要程度。
為了使I(v)和Cs,t(v)有意義,我們規定需要處理的社交網路都是連通的無向圖,即任意兩個結點之間都有一條有限長度的最短路徑。現在給出這樣一幅描述社交網路的加權無向圖,請你求出每一個結點的重要程度。

輸入格式

輸入檔案中第一行有兩個整數,n和m,表示社交網路中結點和無向邊的數目。在無向圖中,我們將所有結點從1 到n 進行編號。接下來m 行,每行用三個整數a,b,c描述一條連線結點a和b,權值為c的無向邊。注意任意兩個結點之間最多有一條無向邊相連,無向圖中也不會出現自環(即不存在一條無向邊的兩個端點是相同的結點)。

輸出格式

輸出檔案包括n行,每行一個實數,精確到小數點後3位。第i行的實數表示結點i在社交網路中的重要程度。

樣例輸入

4 4
1 2 1
2 3 1
3 4 1
4 1 1

樣例輸出

1.000
1.000
1.000
1.000

提示

樣例說明
對於1號結點而言,只有2號到4號結點和4號到2號結點的最短路經過1號結點,而2號結點和4號結點之間的最短路又有2條。因而根據定義,1號結點的重要程度計算為1/2+1/2=1。由於圖的對稱性,其他三個結點的重要程度也都是1。

評分方法
本題沒有部分分,僅當你的程式計算得出的各個結點的重要程度與標準輸出
相差不超過0.001時,才能得到測試點的滿分,否則不得分。

資料規模和約定
50%的資料中:n ≤ 10,m ≤ 45
100%的資料中:n ≤ 100,m ≤ 4500,任意一條邊的權值c 是正整數,滿
足:1 ≤ c ≤ 1000。
所有資料中保證給出的無向圖連通,且任意兩個結點之間的最短路徑數目不
超過10^10。

解題思路

此題n<=100顯然可以使用Floyd來求解.我們把dis[i][j]陣列當做從i到j的最短路的條數,那麼我們在輸入有u,v的一條邊的時候。就應該將dis[u][v]=dis[v][u]=1;因為,如果<u,v>這條邊確實是<u,v>的最短路,那麼dis[u][v]=dis[v][u]=1;若以後發現有與之相同的最短路,就將dis加在一起

if(map[j][k]==map[j][i]+map[i][k])
    dis[j][k]+=dis[j][i]*dis[i][k];

如果<u,v>這條邊不是<u,v>之間的最短路,一定會在以後更新dis[u][v]。

if(map[j][k]>map[j][i]+map[i][k])
{
    map[j][k]=map[j][i]+map[i][k];
    dis[j][k]=dis[j][i]*dis[i][k];
}

最後只要把結果加一下就行了。注意:因為i≠j&&i≠k&&j≠k所以要判斷一下:

if(map[j][k]==map[j][i]+map[i][k]&&i!=j&&j!=k&&i!=k)

#include <stdio.h>
const int inf = 1e9;
int map[110][110], n;
double ans[110], dis[110][110];
void Floyd()
{
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            for (int k = 1; k <= n; k++)
                if (map[j][k] > map[j][i] + map[i][k])
                    map[j][k] = map[j][i] + map[i][k], dis[j][k] = dis[j][i] * dis[i][k];
                else if (map[j][k] == map[j][i] + map[i][k])
                    dis[j][k] += dis[j][i] * dis[i][k];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (i != j)
                for (int k = 1; k <= n; k++)
                    if (k != i && k != j && map[j][k] == map[j][i] + map[i][k])
                        ans[i] += dis[j][i] * dis[i][k] / dis[j][k];
}
int main()
{
    int m, u, v, w;
    while (~scanf("%d%d", &n, &m))
    {
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                map[i][j] = inf;
        for (int i = 0; i < m; i++)
        {
            scanf("%d%d%d", &u, &v, &w);
            map[u][v] = map[v][u] = w;
            dis[u][v] = dis[v][u] = 1;
        }
        Floyd();
        for (int i = 1; i <= n; i++)
            printf("%.3f\n", ans[i]);
    }
    return 0;
}