题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110979#problem/B
代码:
#include<stdio.h> #include<string.h> #include<algorithm> int fa[100005]; int n,m; struct node { int x,y; int w; }q[100005]; using namespace std; int cmp(node a,node b) { return a.w<b.w; } void init() { for(int i=1;i<=n;i++) { fa[i]=i; } } int getf(int u) { if(u==fa[u]) { return fa[u]; } else { fa[u]=getf(fa[u]); return fa[u]; } } int unin(int u,int v) { int a,b; a=getf(u); b=getf(v); if(a!=b) { fa[b]=a; //return 1; } //return 0; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); memset(fa,0,sizeof(fa)); for(int i=0;i<m;i++) { scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].w); } sort(q,q+m,cmp); int temp=0; int ans=0; init(); for(int i=0;i<m;i++) { for(int j=i;q[i].w==q[j].w;j++) { if(getf(q[j].x)!=getf(q[j].y)) // { //printf("%d %d %d %d\n",i,q[i].x,q[i].y,q[i].w); ans++; } } for(int j=i;q[i].w==q[j].w;j++) // { if(getf(q[j].x)!=getf(q[j].y)) unin(q[j].x,q[j].y); } } printf("%d\n",ans); } }
刚开始完全没思路,想了想,发现是最小生成树。经过大神,题解,全方位知道。大致明白了是怎么解的这道题。
以Kruskal算法为基础。
每次找边时(即找ans时)找权值相同且不成环的边。
每次添加的边为权值相同的且不成环。
sort();
i=0时,一定有第一条边为答案。(j=0····)(j=1 break;)
i=1时,找不成环,(j=1···)(j=2 因为权值相等不成环;)也就是说现在找到两个最小生成树 3-4-2 和 4-3-2 现在也就是说有三条边。
考虑i=1是是否找到的边都合并。(不是只合并一次),而是要合并权值相同且不成环的边。若只合并一次,在下一次查找时会多加边(因为上一次已经加了
因为没合并所以现在又加了一遍)。所以要合并权值相同且不成环的边。
<span style="white-space:pre"> </span>int k=1; for(int i=0; i<m; i++) { for(int j=i;q[i].w==q[j].w;j++) { if(getf(q[j].x)!=getf(q[j].y)) { printf("%d %d %d %d\n",i,q[i].x,q[i].y,q[i].w); ans++; } } for(int j=i; k--; j++) { if(getf(q[j].x)!=getf(q[j].y)) { printf(" %d\n",j); unin(q[j].x,q[j].y); //ans=ans+q[i].w; } } k=1; } printf("%d\n",ans);
/* 1 6 6 3 4 1 2 3 2 4 6 2 2 4 2 1 3 100 1 2 101 */