Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
Re:传统做法,枚举最小边,多次执行克鲁斯卡尔算法,49行的AC代码In Reply To:传统做法,枚举最小边,多次执行克鲁斯卡尔算法,49行的AC代码 Posted by:zhouy869 at 2010-08-26 10:50:31 > #include<iostream> > #include<algorithm> > using namespace std; > struct edge > { int from; > int end; > int length; > } E[5000]; > int Eindex[5000];//保存边的编号 > int n,m;//顶点数目,和边数 > int p[101];//记录某个点的父亲节点 > int find(int i) {return p[i]==i?i:p[i]=find(p[i]);}//查找i好节点所在的集合的代表元 > int cmp(const void *a,const void*b) {return E[(*(int*)a)].length- E[(*(int*)b)].length;} > int main() > { while(cin>>n>>m) > { > if(n==0&&m==0)break; > int i=0,j=0; > for(i=1;i<=m;i++) > { cin>>E[i].from>>E[i].end>>E[i].length; Eindex[i]=i; } > qsort(Eindex+1,m,sizeof(Eindex[1]),cmp); //对变得编号排序 > int ans=20050; > for(i=1;i<=m&&(m-(i-1))>=n-1;i++)//从第i小的边开始 执行克鲁斯卡尔算法 > { for(j=0;j<=n;j++)p[j]=j;//初始化p数组 > int esum=0;//记录已经找了多少条边了 > int emax=0;//记录这次求最小生成树的最大边 > for(j=i;j<=m;j++) > { if(esum+(m-(j-1))<n-1||esum==n-1)break; > int index=Eindex[j]; > int x=find(E[index].from); > int y=find(E[index].end); > if(x!=y)//如果两个顶点不在同一个集合(或在说不在同一个连通分量中) > { p[x]=y; //合并两个集合, > esum++; > emax=E[index].length; > } > } > if(esum==n-1)//说明得到一个最小生成树 > { if(emax-E[Eindex[i]].length<ans) > ans=emax-E[Eindex[i]].length; > } > if(ans==0)break; > } > if(ans!=20050) > cout<<ans<<endl; > else cout<<-1<<endl; > } > return 0; > } 这位仁兄的代码还可以加一个小剪枝,就是当在构建某棵树时,slimness已经超过了答案,那么这棵树也就不需要构建完了,直接跳出。 Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator