Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 17785 | Accepted: 6176 |
Description
Input
Output
Sample Input
2 3 3 1 2 1 2 3 2 3 1 3 4 4 1 2 2 2 3 2 3 4 2 4 1 2
Sample Output
3 Not Unique!
题意:有n个点,其中m条边可以连通。求最小生成树是否唯一
这道题一开始没什么特别好的想法,就是想着把最小生成树当中的每一条边都去掉,然后看看生成树的最小路径是否还相同
这道题要虽然是枚举,不过要注意几个方面:
1. 在枚举的过程中,去掉边之后可能就无法得到完整的树。
2. 我在用Prime做的时候,一开始没有考虑清楚一条边的两个端点。wa了好多次。
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #define INF 1000000 //相当于求次小生成树 从最小生成树当中每次删去一边,然后判断生成树是否和最小值相同 //要注意删边之后可能会连通不了 using namespace std; int n,m,p,ans; int map[105][105]; int way[105][2];//用prime算法做的时候,要记录每条边比较麻烦。 //每次加入集合的是点,并不代表最后两个加入的两点之间的那条边就是所取边 //因为这个wa了好多次。。 int prime() { int low[105][2]= {0},visit[105]= {0}; int i,j,ans=0,k; p=0; for (i=0; i<=n; i++) { low[i][0]=map[1][i]; low[i][1]=1; } visit[1]=1; way[p][0]=1; for (i=1; i<n; i++) { int max=INF; k=-1; for (j=1; j<=n; j++) if (!visit[j] && low[j][0]<max) { max=low[j][0]; k=j; } if (k==-1) return 0; way[p][0]=low[k][1]; way[p++][1]=k; visit[k]=1; ans+=low[k][0]; for (j=1; j<=n; j++) if(!visit[j] && low[j][0]>map[k][j]) { low[j][0]=map[k][j]; low[j][1]=k; } } return ans; } int find() { int low[105]= {0},visit[105]= {0}; int i,j,s=0,k; for (i=0; i<=n; i++) low[i]=map[1][i]; visit[1]=1; for (i=1; i<n; i++) { int max=INF; k=-1; for (j=1; j<=n; j++) if (!visit[j] && low[j]<max) { max=low[j]; k=j; } if (k==-1) return -1; visit[k]=1; s+=low[k]; for (j=1; j<=n; j++) if(!visit[j] && low[j]>map[k][j]) low[j]=map[k][j]; } return s; } int main () { int t,i,j; cin>>t; while(t--) { cin>>n>>m; for (i=0; i<=n; i++) { way[i][0]=way[i][1]=0; for (j=0; j<=n; j++) map[i][j]=INF; } for (i=0; i<m; i++) { int a,b,c; cin>>a>>b>>c; map[a][b]=map[b][a]=c; } ans=prime(); int flag=0; int x,y,temp,s; i=0; while(i<p) { x=way[i][0]; y=way[i][1]; temp=map[x][y]; map[x][y]=map[y][x]=INF; s=find(); if (s==ans) { flag=1; break; } map[x][y]=map[y][x]=temp; i++; } if (flag) cout<<"Not Unique!"<<endl; else cout<<ans<<endl; } return 0; }