poj 1679 Kruskal+MST环性质
题意:在一个无向图中,若其最小生成树唯一,则输出其值;若不唯一则输出“Not Unique!”。
《算法:C语言实现》这本书将MST有两个重要性质:割性质和环性质。本题则用到了MST的环性质。也就是说在一个无向连通图中可以将边分为MST上的边和非MST上的边,若将非MST上的边e加入MST中一定会形成一个环。所以先用Kruskal算法求出MST,然后以e的一个端点开始在MST上进行深搜,找到到达另一个端点路径,查看这条路径上边的权值是否有和e的权值相等的。若有则不是唯一的,若将每个e都测试一遍都没有和e的权值相等的则是唯一的。这样说够通俗易懂了吧……然而我看到网上很多人用次小生成树的解法来做,这种解法当然是正确的。但本题只是让判断唯一不唯一,本人认为没必要那样做,我的思路已经说过了,以下是我的代码:
#include<iostream> #include<cstring> #include<vector> using namespace std; struct node { int start; int end; int value; }; struct Adjvex { int v; int value; }; int root[101],wight[101],visit[101]; node ss[10001],tt[10001]; vector <Adjvex> map[101]; bool flag; int cmp(const void* a,const void * b) { return ((node *)a)->value-((node*)b)->value; } int find(int i) { while(root[i]!=i) i=root[i]; return i; } int dfs(int s,int t,int w)//搜索环路径 { int j; visit[s]=1; if(s==t) return 1; for(j=0;j<map[s].size();j++) if(!visit[map[s][j].v] && dfs(map[s][j].v,t,w)) { if(map[s][j].value==w) flag=true; return 1; } //visit[s]=0; return 0; } int Union(int s,int t) { if(wight[s]>=wight[t]) { root[t]=s; wight[s]+=wight[t]; } else { root[s]=t; wight[t]+=wight[s]; } return 0; } int add(node s)//构造MST的数据结构,搜索时用 { Adjvex e={s.end,s.value}; map[s.start].push_back(e); e.v=s.start; map[s.end].push_back(e); return 0; } int main() { int i,k,m,n,N,sum,s,t,count; cin>>n; while(n--) { cin>>m>>k; for(i=0;i<k;i++) cin>>ss[i].start>>ss[i].end>>ss[i].value; qsort(ss,k,sizeof(ss[0]),cmp); for(i=1;i<=m;i++) { root[i]=i; wight[i]=1; } sum=N=count=0; for(i=0;i<k;i++) { s=find(ss[i].start); t=find(ss[i].end); if(s==t) { tt[N++]=ss[i]; continue; } Union(s,t); add(ss[i]); sum+=ss[i].value; //if(count++>=m-1) break; } for(flag=false,i=0;i<N;i++) { memset(visit,0,sizeof(visit)); dfs(tt[i].start,tt[i].end,tt[i].value); if(flag) break; } if(flag) cout<<"Not Unique!"<<endl; else cout<<sum<<endl; for(i=0;i<=m;i++) map[i].clear(); } return 0; }