最小生成树唯一性判断-UESTC1959天才钱vs学霸周
天才钱vs学霸周
Time Limit: 1000 MS Memory Limit: 256 MB
Submit Status
有一天,天才钱
和学霸周
闲的无聊玩起了游戏,游戏内容是这样的,现在有nn个城堡 mm个不同的桥,每一个桥连接着两个不同的城堡,并且已知这mm个桥可以使nn个城堡连通,此外每一个桥都有重量vv。两位大爷需要给出选择桥的方案使得所有城堡被连通,注意两位大爷的方案不能完全相同(至少存在一个桥不相同),已知周大爷
优先给出方案(因此钱大爷
的方案必须不同于周大爷
)。规则很诡异,如果钱大爷
的方案中桥的重量之和≤≤周大爷
的方案中桥的重量之和,那么钱大爷
获胜,反之周大爷
获胜。两位大爷都很聪明,他们会给出最优方案。现在你需要计算谁会赢。
Input
第一行输入两个值nn(2≤n≤20002≤n≤2000),mm (n≤m≤200000n≤m≤200000) 接下来mm行,每一行输入三个值aa (1≤a≤n1≤a≤n),bb(1≤b≤n1≤b≤n),vv(1≤v≤10181≤v≤1018),其中a!=ba!=b
Output
如果钱大爷
获胜输出“zin
”,反之输出“ogisosetsuna
” 。
Sample input and output
Sample Input | Sample Output |
---|---|
2 2 1 2 1 1 2 1 | zin |
Hint
样例和test1不同
Source
2018 UESTC ACM Training for Graph Theory
题解:其实就是最小生成树唯一性的判定Orz......;
利用并查集,按边权从小到大排序,然后对于每一个权值对应的边,先查找边的两个点不在同一集合的数量cnt1,然后再边枚举每一条不在同一集合的,并将边的两点合并到同一集合,计算数量cnt2,,对于每一权值,如果有cnt1>cnt2这说明最小生成树不唯一。
AC代码为:
#include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; const int N=2000+10; const int M=200000+10; int fa[N]; map<LL,int> mm; vector<int> E[M]; struct node{ int u,v; LL w; }edge[M]; bool cmp(node a,node b) { return a.w<b.w; } void init() { for(int i=0;i<N;i++) fa[i]=i; } int fi(int x) { return x==fa[x]?x:fa[x]=fi(fa[x]); } void Union(int x,int y) { int fx=fi(x),fy=fi(y); if(fx!=fy) fa[fx]=fy; } int main() { init(); int n,m,cnt=1; int cnt1=0,cnt2=0; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%lld",&edge[i].u,&edge[i].v,&edge[i].w); sort(edge+1,edge+1+m,cmp); for(int i=1;i<=m;i++){ if(!mm[edge[i].w]) mm[edge[i].w]=cnt,cnt++; int pos=mm[edge[i].w]; E[pos].push_back(i); } for(int i=1;i<cnt;i++) { for(int j=0;j<E[i].size();j++) { int pos=E[i][j]; if(fi(edge[pos].u)!=fi(edge[pos].v)) cnt1++; } for(int j=0;j<E[i].size();j++) { int pos=E[i][j]; if(fi(edge[pos].u)!=fi(edge[pos].v)) { Union(edge[pos].u,edge[pos].v); cnt2++; } } if(cnt1>cnt2) break; } if(cnt1>cnt2) printf("zin\n"); else printf("ogisosetsuna\n"); return 0; }