1. 程式人生 > >codevs 1078最小生成樹 Kruskal+並查集

codevs 1078最小生成樹 Kruskal+並查集

路徑壓縮 nbsp 空格 長度 scan return fin kruskal esc

題目描述 Description

農民約翰被選為他們鎮的鎮長!他其中一個競選承諾就是在鎮上建立起互聯網,並連接到所有的農場。當然,他需要你的幫助。 約翰已經給他的農場安排了一條高速的網絡線路,他想把這條線路共享給其他農場。為了使花費最少,他想鋪設最短的光纖去連接所有的農場。 你將得到一份各農場之間連接費用的列表,你必須找出能連接所有農場並所用光纖最短的方案。 每兩個農場間的距離不會超過100000

輸入描述 Input Description

第一行: 農場的個數,N(3<=N<=100)。

第二行..結尾: 接下來的行包含了一個N*N的矩陣,表示每個農場之間的距離。理論上,他們是N行,每行由N個用空格分隔的數組成,實際上,他們每行限制在80個字符以內,因此,某些行會緊接著另一些行。當然,對角線將會是0,因為線路從第i個農場到它本身的距離在本題中沒有意義。

輸出描述 Output Description

只有一個輸出,是連接到每個農場的光纖的最小長度和。

樣例輸入 Sample Input

4

0 4 9 21

4 0 8 17

9 8 0 16

21 17 16 0

樣例輸出 Sample Output

28

思路:用結構體存邊(如果邊權為0可以跳過,也就是說(n.n)可以跳過,不存入邊中 ),sort一下,使用並查集存不同的樹,最後gg。

(類似貪心的思路)

Kruskal:

最開始把每個端點的根節點存為自己,然後不停的模擬建樹(我也不知道這樣的說法對不對,唔)。

每次尋找最小的邊,判斷這條邊的起點的根節點是否與這條邊的根節點相同。如果不相同,證明這兩個點不在同一個樹中。然後將一個根節點存為另一個根節點的父節點(即把兩棵樹存為一棵樹)。(每次找到可以存的邊,邊樹++)

最後,如果邊數==端點個數-1,輸出路徑的長度,直接打斷return 0

代碼實現:

#include<stdio.h>
#include<algorithm>
using namespace std;
struct edge
{
int u;
int v;
int w;
}e[400000];
int flag,pre[1000],ans,n,cnt,t;

//pre記錄當前端點的父節點
int judge(int x)
{
int j;
j=x;
while(j!=pre[j])
{
j=pre[j];
}
int i;
i=x;
while(i!=j)
{
i=pre[i];
pre[i]=j;
}

//路徑壓縮
return j;
}

//找到當前邊起點/終點的根節點
void find(int x)
{
int a,b;
a=judge(e[x].u);
b=judge(e[x].v);
if(a!=b)
{
pre[a]=b;
flag=1;
}
}
bool cmp(edge a,edge b)
{
return a.w<b.w;
}
int main()
{
int w;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
pre[i]=i;
for(int j=1;j<=n;j++)
{
scanf("%d",&w);
if(w!=0)
{
e[++cnt].u=i;
e[cnt].v=j;
e[cnt].w=w;
}
}
}
sort(e+1,e+cnt+1,cmp);
for(int i=1;i<=cnt;i++)
{
flag=0;
find(i);
if(flag==1)
{
ans=ans+e[i].w;
t++;
}
if(t==n-1)
{
printf("%d",ans);
return 0;
}
}
}

ps:小白第一次寫博客,給位看官如果發現錯誤請幫忙糾正,求輕噴。

codevs 1078最小生成樹 Kruskal+並查集