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 }