時限: 1000MS | 內存: 32768KB | 64位IO格式: %I64d & %I64u |
輸入
行對應村莊間道路的成本,每行給出一對正整數,分別是兩個村莊的編號,以及此兩村莊間道路的成本(也是正整數)。爲簡單起見,村莊從1到M編號。當N爲0時,全部輸入結束,相應的結果不要輸出。
輸出
樣例輸入
樣例輸出
思路:
最小生成樹 杭電 1863 點擊打開鏈接
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int pre[1005];
struct node
{
int p1;
int p2;//p1,p2分別對應的兩個居民點
int v;//鋪設管道所需的費用
} way[1005];
int m,n;
void init()
{
memset(pre,0,sizeof(pre));
memset(way,0,sizeof(way));
for(int i=1;i<=m;i++)//初始化,每一個點當做是一個父節點
pre[i]=i;
}
int cmp(node a,node b)
{
return a.v<b.v;
}
int find(int x)//查找父節點
{
int ret=x;
while(pre[ret]!=ret) //如果查找到的父節點不是它本身,就直接把它當做一個新的父節點
ret=pre[ret];
int t=x,r;//下面是路徑壓縮
while(t!=ret)
{
r=pre[t]; //在改變上一級額的父節點之前 用臨時變量將它記錄起來
pre[t]=ret;//把上級節點改爲父節點
t=r;
}
return ret;
}
int join(int x,int y) //判斷兩個點是否連通
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)//如果已經聯通就不用管,否則將它併入之前的連通分支中
{
pre[fx]=fy;
return 1;
}
return 0;
}
int main()
{
while(scanf("%d%d",&n,&m),n)
{
init();
for(int i=0;i<n;i++)
scanf("%d%d%d",&way[i].p1,&way[i].p2,&way[i].v);
sort(way,way+n,cmp); //排序,目的是爲了優先考慮成本低的將它併入連通分支
int ans=0;
for(int i=0;i<n;i++)
if(join(way[i].p1,way[i].p2))//如果已經聯通就只需計算管道費用就行
ans+=way[i].v;
int count=0;
for(int i=1;i<=m;i++)
if(pre[i]==i)//判斷是否都連通
count++;
if(count>1)//如果不連通
printf("?\n");
else
printf("%d\n",ans);
}
return 0;
}