EOJ-2614 组网计划

http://acm.cs.ecnu.edu.cn/problem.php?problemid=2614

题意:求其最小生成树,且判断最小生成树是否唯一。

prim法,判断唯一的方法:进行两次prim,第一次,每次加最小边时当出现多个最小边时,总是添加结点编号较小的那个,而第二次总是添加较大那个 (即若总是无多个最小边选择,最小生成树必是唯一的),若生成树是完全相同的则唯一,方法是:两次分别记录加边的情况,若加边情况相同则其唯一,否则有多个解。

 1 #include<map>
 2 #include<set>
 3 #include<list>
 4 #include<cmath>
 5 #include<ctime>
 6 #include<queue>
 7 #include<stack>
 8 #include<cctype>
 9 #include<cstdio>
10 #include<string>
11 #include<cstdlib>
12 #include<cstring>
13 #include<iostream>
14 #include<algorithm>
15 using namespace std;
16 const int inf=0x3f3f3f3f;
17 int mat[105][105];
18 int n;
19 int a[105],b[105];        //记录加边顺序
20 void init(){
21     for(int i=1;i<=n;i++)
22         for(int j=1;j<=n;j++)
23         mat[i][j]=inf;
24 }
25 int prim(bool flag){
26     int lowcost[105],s[105];
27     int ans=0;
28     for(int i=1;i<=n;i++){
29         lowcost[i]=mat[1][i];
30         s[i]=0;
31     }
32     s[1]=1;
33     for(int i=1;i<=n;i++){
34         int min=inf,k;
35         if(flag){
36             for(int j=1;j<=n;j++)
37                 if(!s[j] && lowcost[j]<=min){            //"<="判断条件使得可有多个选择,并总是更新编号较大的
38                     min=lowcost[j];
39                     k=j;
40                     a[i]=k;                                //记录加边顺序
41                 }
42         }else{
43             for(int j=n;j>=1;j--)                        //总是更新编号较小的
44                 if(!s[j] && lowcost[j]<=min){
45                     min=lowcost[j];
46                     k=j;
47                     b[i]=k;                                //记录加边顺序
48                 }
49         }
50         if(min==inf) break;
51         ans+=min;
52         s[k]=1;
53         for(int j=1;j<=n;j++)
54             if(!s[j] && mat[k][j]<lowcost[j])
55                 lowcost[j]=mat[k][j];
56     }
57     return ans;
58 }
59 int main(){
60     while(~scanf("%d",&n)){
61         init();                            //初始化
62         int x[105],y[105];
63         for(int i=1;i<=n;i++)
64             scanf("%d%d",x+i,y+i);
65         for(int i=1;i<=n;i++)
66             for(int j=i+1;j<=n;j++)
67                 mat[i][j]=mat[j][i]=abs(x[i]-x[j])+abs(y[i]-y[j]);    //建图用的曼哈顿距离
68         int reta=prim(1),retb=prim(0);        //进行两次prim,参数1代表总是取较大边,0代表总是取较小边
69         printf("%d
",reta);
70         bool f=0;
71         for(int i=1;i<n;i++)
72             if(a[i]!=b[i]){printf("Yes
");f=1;break;}            //若加边顺序不同一定有多种情况
73         if(!f)printf("No
");
74     }
75     return 0;
76 }
View Code
原文地址:https://www.cnblogs.com/KimKyeYu/p/3149223.html