http://acm.hdu.edu.cn/showproblem.php?pid=1863
还是最小生成树,还是用了kruskal写,就是有点不一样的地方在于,他要让你判断是否能够保证畅通,也就是是否能有最小生成树,其实就是判断是不是连通图吧,因为连通图一定会有最小生成树。
一开始我的想法是,先进行一次并查集的合并与查找,看一下有几个集合,如果只有一个集合的话就是连通图,肯定有最小生成树存在,如果多余一个集合就不会有,直接输出问好。之后要记得还原根节点。。
附上代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define M 1000000 int u[M],v[M],p[M],w[M]; int r[M],t[M]; int n,m; int ans; int cmp(int a,int b) { return w[a] < w[b]; } int find(int x) { return p[x]==x?x:p[x]=find(p[x]); } void uni(int x,int y) { if(x!=y) p[x] = y; } int kruskal() { for(int i = 0;i < n;i++) { int e = r[i]; int x = find(u[e]),y = find(v[e]); if(x!=y) { p[x] = y; ans += w[e]; } } } int main() { while(scanf("%d %d",&n,&m)==2 && n) { memset(t,0,sizeof(t)); ans = 0; int num = 0; for(int i = 1;i <= m;i++) p[i] = i; for(int i = 0;i < n;i++) r[i] = i; for(int i = 0;i < n;i++) { scanf("%d%d%d",&u[i],&v[i],&w[i]); uni(u[i],v[i]); } for(int i = 1;i <=m;i++) { int temp = find(i); if(t[temp]==0) { num++; t[temp]++; } } if(num!=1) { printf("?\n"); continue; } for(int i = 1;i <= m;i++) p[i] = i; sort(r,r+n,cmp); kruskal(); printf("%d\n",ans); } return 0; }
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define M 1000000 int u[M],v[M],p[M],w[M]; int r[M],t[M]; int n,m; int ans; int cmp(int a,int b) { return w[a] < w[b]; } int find(int x) { return p[x]==x?x:p[x]=find(p[x]); } bool kruskal() { int sum = 0; for(int i = 0;i < n;i++) { int e = r[i]; int x = find(u[e]),y = find(v[e]); if(x!=y) { p[x] = y; ans += w[e]; sum++; } } if(sum < m-1) return false; return true; } int main() { while(scanf("%d %d",&n,&m)==2 && n) { memset(t,0,sizeof(t)); ans = 0; int num = 0; for(int i = 1;i <= m;i++) p[i] = i; for(int i = 0;i < n;i++) r[i] = i; for(int i = 0;i < n;i++) { scanf("%d%d%d",&u[i],&v[i],&w[i]); } sort(r,r+n,cmp); bool ok = kruskal(); if(ok) printf("%d\n",ans); else printf("?\n"); } return 0; }