Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 23180 | Accepted: 8235 |
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!
Source
对于最小生成树(可以用kruskal和prime算法求得,在这里我是用kruskal求得,如果不会请自己百度。),边的权值的和最小称为最小生成树。
而次小生成树就是除了最小生成树外的最小生成树。而且所有的次小生成树都是通过最小生成树的换边得到的。
所以难点就是如何换边。
对于如何换边:
1.先求出最小生成树,值为x。
2.一一枚举添加不在生成树上的边(这时候一定形成了一个环)
3.寻找环上的(最小生成树上的边)权值最大值与你所添加不在生成树上的边的权值比较,所得到的差值为min。
由于是一一枚举添加边,min有多个,求出最小的哪一个,所以次小生成树就为x+min。
昨天虽然把这道题A了,可是看到讨论区的测试数据发现自己又一个没有过,然而却AC了。然后今天起床就来研究研究。。。
发现我的程序是在找最大值,可是如果一个环有分支,它还会去找分支里面的最大值,于是就又优化了一下。
用的优先队列。
先附上第一次做的代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; struct node { int a,b,cost; }c[10005]; int fa[105],tree[105][105],vis[10005],vis_tree[105];//vis数组是对m对数据的标记vis_tree是对最小生成树标记 int n,m,max1; bool cmp(node x,node y) { if(x.cost<y.cost) return true; else return false; } int find(int x)//寻找根 { if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void sec_tree(int a,int b)//查找生成树某条边的最大值(我在这里做的是错误的,如果形成的环有分支,也会查找) { vis_tree[a]=1; if(a==b) return ; for(int i=1;i<=n;i++) if(tree[a][i]&&!vis_tree[i]) { if(max1<tree[a][i]) max1=tree[a][i]; sec_tree(i,b); } } int main() { int ncase; scanf("%d",&ncase); while(ncase--) { memset(vis,0,sizeof(vis)); memset(tree,0,sizeof(tree)); memset(&c,0,sizeof(&c)); scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) fa[i]=i; for(int i=0;i<m;i++) scanf("%d %d %d",&c[i].a,&c[i].b,&c[i].cost); sort(c,c+m,cmp); int sum=0; for(int i=0;i<m;i++)//kruskal算法求最小生成树 { int x=find(c[i].a); int y=find(c[i].b); if(x!=y) { fa[x]=y,sum+=c[i].cost; tree[x][y]=tree[y][x]=c[i].cost; vis[i]=1; } } int flag=0; for(int i=0;i<m;i++) { if(!vis[i])//不在生成树中的边和形成的环的最大值比较。如果相等,MST不唯一 { max1=-1; memset(vis_tree,0,sizeof(vis_tree)); sec_tree(c[i].a,c[i].b); if(max1==c[i].cost) { flag=1; break; } } } if(!flag) printf("%d\n",sum); else printf("Not Unique!\n"); } }
#include <stdio.h> #include <string.h> #include <algorithm> #include <queue> using namespace std; struct node1 { int a,b,cost; friend bool operator<(node1 x,node1 y ) { return x.cost<y.cost; } }; priority_queue<node1>s; struct node { int a,b,cost; }c[10005]; int fa[105],tree[105][105],vis[10005],vis_tree[105]; int n,m,max1,flag1; bool cmp1(node x,node y) { if(x.cost<y.cost) return true; else return false; } int find(int x) { if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void sec_tree(int a,int b) { node1 temp; vis_tree[a]=1; if(a==b)//如果找到a=b,标记一下 { flag1=1; } for(int i=1;i<=n;i++) if(tree[a][i]&&!vis_tree[i]) { temp.a=a,temp.b=i,temp.cost=tree[a][i]; s.push(temp); if(!flag1)//就是在这里和上面不同,如果找不到a=b,那么就把以前的恢复 s.pop(),vis_tree[i]=0,sec_tree(i,b); } } int main() { int ncase; scanf("%d",&ncase); while(ncase--) { memset(vis,0,sizeof(vis)); memset(tree,0,sizeof(tree)); memset(&c,0,sizeof(&c)); scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) fa[i]=i; for(int i=0;i<m;i++) scanf("%d %d %d",&c[i].a,&c[i].b,&c[i].cost); sort(c,c+m,cmp1); int sum=0; for(int i=0;i<m;i++) { int x=find(c[i].a); int y=find(c[i].b); if(x!=y) { fa[x]=y,sum+=c[i].cost; tree[x][y]=tree[y][x]=c[i].cost; vis[i]=1; } } int flag=0; for(int i=0;i<m;i++) { if(!vis[i]) { int flag1=0; while(!s.empty()) s.pop(); memset(vis_tree,0,sizeof(vis_tree)); sec_tree(c[i].a,c[i].b); node1 temp; temp=s.top(); if(temp.cost==c[i].cost) { flag=1; break; } } } if(!flag) printf("%d\n",sum); else printf("Not Unique!\n"); } }