Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 26460 | Accepted: 9462 |
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!
题意:图中最小生成树是否唯一。唯一输出最小生成树长度,不唯一输出Not Unique!
思路:求出次小生成树,然后比较下是否相等,相等则不唯一。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define N 110 #define INF 1<<30 int ma[N][N];///ma数组用来保存初始图 int p[N],d[N],path[N][N];///p是每个城市的人口,d用来维护当前最短距离,path用来记录最小生成树上两点之间所有路径中的单边最大权值 int flag[N],pre[N],n,used[N][N];///flag数组标记当前点是否已经在最小生成树里,pre记录当前点的前驱(因为是无向图,其实也就是一条边的另一个节点) ///used[i][j]用来记录边ij有没有在最小生成树上,0是不在,1是在 int prim() { int ret=0;///最小生成树大小 memset(flag,0,sizeof(flag)); memset(used,0,sizeof(used)); memset(path,0,sizeof(path));///题目边都是大于0的,所以置为0就好 for(int i=1; i<n; i++) { d[i]=ma[0][i]; pre[i]=0; } flag[0]=1; for(int i=1; i<n; i++) { int v=-1; for(int j=0; j<n; j++) if(!flag[j]&&(v==-1||(d[v]>d[j]))) v=j; if(v==-1) return -1; used[v][pre[v]]=used[pre[v]][v]=1; ret+=d[v]; flag[v]=1; for(int j=0; j<n; j++) { if(flag[j]&&j!=v) path[j][v]=path[v][j]=max(path[pre[v]][j],d[v]); if(!flag[j]&&d[j]>ma[v][j]) { d[j]=ma[v][j]; pre[j]=v; } } } return ret; } int main() { int T,m; int u,v,w; scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); for(int i=0; i<n; i++) for(int j=0; j<n; j++) ma[i][j]=INF; for(int i=0; i<m; i++) { scanf("%d %d %d",&u,&v,&w); ma[u-1][v-1]=ma[v-1][u-1]=w; } int ret=prim(); int ans=INF; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { if(i==j) continue; if(ma[i][j]!=INF&&!used[i][j]) ans=min(ans,ret-path[i][j]+ma[i][j]); } } if(ans==ret) printf("Not Unique!\n"); else printf("%d\n",ret); } return 0; }
int ma[N][N];///ma数组用来保存初始图 int p[N],d[N],path[N][N];///p是每个城市的人口,d用来维护当前最短距离,path用来记录最小生成树上两点之间所有路径中的单边最大权值 int flag[N],pre[N],n,used[N][N];///flag数组标记当前点是否已经在最小生成树里,pre记录当前点的前驱(因为是无向图,其实也就是一条边的另一个节点) ///used[i][j]用来记录边ij有没有在最小生成树上,0是不在,1是在 int prim() { int ret=0;///最小生成树大小 memset(flag,0,sizeof(flag)); memset(used,0,sizeof(used)); memset(path,0,sizeof(path));///题目边都是大于0的,所以置为0就好 for(int i=1; i<n; i++) { d[i]=ma[0][i]; pre[i]=0; } flag[0]=1; for(int i=1; i<n; i++) { int v=-1; for(int j=0; j<n; j++) if(!flag[j]&&(v==-1||(d[v]>d[j]))) v=j; if(v==-1) return -1; used[v][pre[v]]=used[pre[v]][v]=1;///标记最小生成树上的边 ret+=d[v]; flag[v]=1; for(int j=0; j<n; j++) { if(flag[j]&&j!=v) path[j][v]=path[v][j]=max(path[pre[v]][j],d[v]); if(!flag[j]&&d[j]>ma[v][j]) { d[j]=ma[v][j]; pre[j]=v; } } } return ret; } int next(int ret)///求次小生成树长度 { int ans=INF; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { if(i==j) continue; if(ma[i][j]!=INF&&!used[i][j]) ans=min(ans,ret-path[i][j]+ma[i][j]); } } return ans; }