問題描述
某省調查鄉村交通狀況,得到的統計表中列出了任意兩村莊間的距離。省政府“暢通工程”的目標是使全省任何兩個村莊間都可以實現公路交通(但不一定有直接的公路相連,只要能間接通過公路可達即可),並要求鋪設的公路總長度爲最小。請計算最小的公路總長度。
輸入
測試輸入包含若干測試用例。每個測試用例的第1行給出村莊數目N ( < 100 );隨後的N(N-1)/2行對應村莊間的距離,每行給出一對正整數,分別是兩個村莊的編號,以及此兩村莊間的距離。爲簡單起見,村莊從1到N編號。
當N爲0時,輸入結束,該用例不被處理。
輸出
對每個測試用例,在1行裏輸出最小的公路總長度。
Sample Input
3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0
Sample Output
3 5
Sample Input
3 (1 2 1) (1 3 2) (2 3 4)
4 (1 2 1 )(1 3 4) (1 4 1) (2 3 3) (2 4 2) (3 4 5)
0
連通並且最短距離,顯然是最小生成樹問題。
最小生成樹問題有兩種基本解決算法:
(1)prim算法(加點法)
(2)kruskal算法(加邊法)
法一:prim算法
加點法。
初始化點1,設置爲已訪問visit[1]=1。將每個未訪問點到訪問點的最短距離初始化爲到點1 的距離,dis[j]=map[1][j]。
不斷選擇未訪問到訪問點的最短距離dis[n],加入最短距離,將最短距離的點設置爲已訪問。
重新計算每個未訪問點的最短距離。
對n-1個點進行選擇。(n-1次循環)
#include <stdio.h>
#include <string.h>
#define MAXN 100000
#define N 110
int map[N][N];
int visit[N];
int dis[N];
int prime(int n)
{
int i,j,min,k,s=0;
memset(visit,0,sizeof(visit));
for(i=1;i<=n;i++)
dis[i]=map[1][i];
visit[1]=1;
for(i=1;i<n;i++) //n-1個點
{
min=MAXN;
for(j=1;j<=n;j++)
{
if(visit[j]==0&&dis[j]<min) //從1出發選擇一條最短的路
{
min=dis[j];
k=j;
}
}
visit[k]=1; //k也訪問過了,更新所有未訪問過的最短距離
s=s+dis[k];
for(j=1;j<=n;j++)
{
if(visit[j]==0&&dis[j]>map[k][j])
{
dis[j]=map[k][j];
}
}
}
return s;
}
int main()
{
int n,i,j,x,y,s,m,sum=0;
while(scanf("%d",&n))
{
if(n==0) break;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
map[i][j]=MAXN;
m=n*(n-1)/2;
while(m--)
{
scanf("%d %d %d",&x,&y,&s);
map[x][y]=map[y][x]=s;
}
sum=prime(n);
printf("%d\n",sum);
}
return 0;
}
法二:kruskal算法
加邊法。在這裏我使用了並查集,來判斷新加入的邊的兩點是否已經連通。
對所有的邊進行排序,從小到大 的選擇邊,判斷即將加入的邊的兩點是否已經連通,是則不加入,否則加入。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 10000
typedef struct _node{
int val;
int start;
int end;
}Node;
Node V[N];
int f[N];
void init(int n)
{
int i;
for(i=1;i<=n;i++)
f[i]=i;
}
int find(int x)
{
while(x!=f[x])
x=f[x];
return x;
}
void merge(int x,int y)
{
int xx=find(x);
int yy=find(y);
if(x!=y)
f[xx]=yy;
}
int kruskal(int n)
{
int i,x,y,s=0;
int m=n*(n-1)/2;
init(n);
for(i=0;i<m;i++)
{
x=V[i].start;
y=V[i].end;
if(find(x)!=find(y))
{
merge(x,y);
s+=V[i].val;
}
}
return s;
}
void initv(int m)
{
int i,x,y,s;
for(i=0;i<m;i++)
{
scanf("%d %d %d",&x,&y,&s);
V[i].start=x;
V[i].end=y;
V[i].val=s;
}
}
int cmp(const void *a, const void *b)
{
return(*(Node *)a).val - (*(Node*)b).val;
}
int main()
{
int n,i,j,x,y,s,m,sum=0;
while(scanf("%d",&n))
{
if(n==0) break;
int m=n*(n-1)/2;
initv(m);
qsort(V,m,sizeof(V[0]), cmp);
sum=kruskal(n);
printf("%d\n",sum);
}
return 0;
}