[BZOJ] 1491 [洛谷] P2047 [NOI2007] 社交網路
Description
在社交網路(socialnetwork)的研究中,我們常常使用圖論概念去解釋一些社會現象。不妨看這樣的一個問題。
在一個社交圈子裡有n個人,人與人之間有不同程度的關係。我們將這個關係網路對應到一個n個結點的無向圖上,
兩個不同的人若互相認識,則在他們對應的結點之間連線一條無向邊,並附上一個正數權值c,c越小,表示兩個人
之間的關係越密切。我們可以用對應結點之間的最短路長度來衡量兩個人s和t之間的關係密切程度,注意到最短路
徑上的其他結點為s和t的聯絡提供了某種便利,即這些結點對於s和t之間的聯絡有一定的重要程度。我們可以通過
統計經過一個結點v的最短路徑的數目來衡量該結點在社交網路中的重要程度。考慮到兩個結點A和B之間可能會有
多條最短路徑。我們修改重要程度的定義如下:令Cs,t表示從s到t的不同的最短路的數目,Cs,t(v)表示經過v從s
到t的最短路的數目;則定義
為結點v在社交網路中的重要程度。為了使I(v)和Cs,t(v)有意義,我們規定需要處理的社交網路都是連通的無向圖
,即任意兩個結點之間都有一條有限長度的最短路徑。現在給出這樣一幅描述社交網路的加權無向圖,請你求出每
一個結點的重要程度。
Input
輸入第一行有兩個整數n和m,表示社交網路中結點和無向邊的數目。在無向圖中,我們將所有結點從1到n進行編號
。接下來m行,每行用三個整數a,b,c描述一條連線結點a和b,權值為c的無向邊。注意任意兩個結點之間最多有
一條無向邊相連,無向圖中也不會出現自環(即不存在一條無向邊的兩個端點是相同的結點)。n≤100;m≤4500
,任意一條邊的權值 c 是正整數,滿足:1≤c≤1000。所有資料中保證給出的無向圖連通,且任意兩個結點之間
的最短路徑數目不超過 10^10
Output
輸出包括n行,每行一個實數,精確到小數點後3位。第i行的實數表示結點i在社交網路中的重要程度。
Sample Input
4 4
1 2 1
2 3 1
3 4 1
4 1 1
Sample Output
1.000
1.000
1.000
1.000
HINT
社交網路如下圖所示。
對於 1 號結點而言,只有 2 號到 4 號結點和 4 號到 2 號結點的最短路經過 1 號結點,而 2 號結點和 4 號結
點之間的最短路又有 2 條。因而根據定義,1 號結點的重要程度計算為 1/2 + 1/2 = 1 。由於圖的對稱性,其他
三個結點的重要程度也都是 1 。
這是一道年代久遠的NOI水題,我們可以明確地知道這道題要用最短路來寫。
既然n<=100所以直接用floyd就可以寫,而且程式碼量很小。
具體來說:
我們需要新增一個數組road記錄下從點i到點j的最短路的數量。
先初始化陣列,若兩個點i,j之間有連邊,那麼road[i][j]=1。由於是無向圖,road[j][i]=1。
在跑floyd的過程中,我們在更新最短路長度的同時,同步更新最短路徑的數量。
if(Map[i][j]>Map[i][k]+Map[k][j])//如果發現更優的線路,那麼最短路徑數就更新為
{ //i到k的最短路徑數*j到k的最短路徑數。
Map[i][j]=Map[i][k]+Map[k][j];//至於為什麼是*可以去問下你的初中數學老師。
road[i][j]=road[i][k]*road[k][j];
}
else if(Map[i][j]==Map[i][k]+Map[k][j])//如果發現了另一條同樣優的最短路
road[i][j]+=road[i][k]*road[k][j];//那麼最短路徑數就加上i到k的路徑數*k到j的路徑數。
跑完之後就是一個模擬的過程了。
列舉每一個點,再列舉所有的起點和終點,將經過這個點的路徑數加起來再除掉總路徑數。
for(int k=1;k<=n;k++)
{
double ans=0;
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
if(k!=i&&k!=j&&j!=i)
if(Map[i][j]==Map[i][k]+Map[k][j]&&road[i][j]!=0)
ans+=(double)road[i][k]*road[k][j]/road[i][j];
printf("%.3f\n",ans);//和上面floyd的過程其實挺像的。
}
所以說洛谷的難度標籤還是不可信的,這道題明顯只有普及組的難度。
下面放出完整程式碼供大家抄襲參考。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long Map[1005][1005],road[1005][1005];
long long x,y,z,n,m;
int main()
{
cin>>n>>m;
memset(Map,11,sizeof(Map));
for(int i=1;i<=m;i++)
{
cin>>x>>y>>z;
Map[x][x]=0;
Map[y][y]=0;
Map[x][y]=min(Map[x][y],z);
Map[y][x]=Map[x][y];
road[x][y]=1;
road[y][x]=1;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(Map[i][j]>Map[i][k]+Map[k][j])
{
Map[i][j]=Map[i][k]+Map[k][j];
road[i][j]=road[i][k]*road[k][j];
}
else if(Map[i][j]==Map[i][k]+Map[k][j])
road[i][j]+=road[i][k]*road[k][j];
}
for(int k=1;k<=n;k++)
{
double ans=0;
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
if(k!=i&&k!=j&&j!=i)
if(Map[i][j]==Map[i][k]+Map[k][j]&&road[i][j])
ans+=(double)road[i][k]*road[k][j]/road[i][j];
printf("%.3f\n",ans);
}
return 0;
}