题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6081
题目大意:给你一个连通图,你可以减掉一些连通分量,让它变为非连通图,输出去掉多少连通分量(最少),图为非连通图
题目思路:
一、首先你要确定该图是连通图,如果不是则输出0,图内一共有N个点,那么根据并查集的性质,会有N-1个点并入到某一个点为根节点的集合中去,所以设Cnt=N-1,每次合并的时候Cnt--;
二、Sum[i]数组存储每个点的连通值,即每个点与其他点连接时的权值的和(千万要记住自己与自己链接的权值不要加和)
三、如果所有的边权都输入了,不是连通图输出0,是连通图,遍历每一个点的Sum值,输出最小的Sum值
题目坑点:同一个点的权值不要加和!!!!这个题目一个点一个点的撕就可以,可能是因为数据弱的原因。
学到的东西:并查集的运用:N个点合并N-1次,则为连通图。做图论相关的题目,一定要讨论两点相同的情况。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3005;
const int inf = 0x3ffffff;
int pre[maxn];
int sum[maxn];
void build(int n)
{
for(int i=0;i<=n;i++)
pre[i]=i,sum[i]=0;
}
int find(int x)
{
int p,tmp;
p=x;
while(x!=pre[x]) x=pre[x];
while(p!=x){
tmp=pre[p];
pre[p]=x;
p=tmp;
}
return x;
}
bool join(int x,int y)
{
int p=find(x);
int q=find(y);
if(p!=q){
pre[p]=q;
return true;
}
return false;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
int cnt=n-1;
build(n);
while(m--){
int x,y,val;
scanf("%d%d%d",&x,&y,&val);
if(x==y) continue;//如果是同一个点,就没有处理的必要性了
sum[x]+=val,sum[y]+=val;
if(join(x,y)) cnt--;
}
if(cnt!=0) printf("0\n");
else{
int mmin=inf;
for(int i=1;i<=n;i++)
if(sum[i]<mmin) mmin=sum[i];
printf("%d\n",mmin);
}
}
return 0;
}