关押罪犯
题目:
https://ac.nowcoder.com/acm/problem/16591
思路一:
用贪心
首先通过冲突从大到小排序
通过扩展域并查集尽可能的把冲突大的分别分到两个不同的监狱,直到要分的两个已经在一个集合,那就得到最大值最小的那个了
遍历的时候清醒一点,不要把n,m搞混了
#include<stdio.h> #include<algorithm> using namespace std; const int maxn=4e4+7; const int mm=1e5+7; int f[maxn]; int find(int x) { return x==f[x]?x:f[x]=find(f[x]); } struct pri { int a,b,c; }; struct pri p[mm]; int cmp(pri q,pri w) { return q.c>w.c; } void merge(int x,int y) { int fx=find(x); int fy=find(y); f[fx]=fy; } int main() { int n,m; scanf("%d %d",&n,&m); for(int i=1;i<=2*n;i++) f[i]=i; for(int i=1;i<=m;i++) { scanf("%d %d %d",&p[i].a,&p[i].b,&p[i].c); } sort(p+1,p+m+1,cmp); int i; int flag=0; for(i=1;i<=m;i++) { int x=p[i].a; int y=p[i].b; if(find(x)==find(y)) { printf("%d\n",p[i].c); flag=1; break; } merge(x,y+n); merge(x+n,y); } if(flag==0) printf("0\n"); return 0; }
思路二:用二分加染色
(ps:一定要分清楚n,m,maxn,maxm,我容易写着写着就混了)
二分来check(middle)
check的时候,如果小于mid是可以不管的,注意每次Check要初始化,而且大于Mid的要连边;
dfs,没染色 的时候是-1,有边的两个点必须是不同颜色的,如果碰到连边的两个点都染色了且不同return 0;
特判0
#include<bits/stdc++.h> using namespace std; const int maxn=2e4+7; const int maxm=1e5+7; int n,m,l,r,mid; int col[maxn]; vector<int> q[maxn]; struct edge { int u,v,w; }e[maxm]; int cmp(edge a,edge b) { return a.w>b.w; } int dfs(int x) { for(int i=0;i<q[x].size();i++) { int t=q[x][i]; if(col[t]==-1) { col[t]=col[x]^1; if(dfs(t)==0) return 0; } else if(col[t]!=(col[x]^1)) return 0; } return 1; } int check(int x) { for(int i=1;i<=n;i++) { q[i].clear(); col[i]=-1; } for(int i=1;i<=m;i++) { if(e[i].w<x) break; int x=e[i].u; int y=e[i].v; q[x].push_back(y); q[y].push_back(x); } for(int i=1;i<=n;i++) { if(col[i]==-1) { col[i]=2; if(dfs(i)==0) return 0; } } return 1; } int main() {scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w); sort(e+1,e+m+1,cmp); l=0,r=1e9; if(check(0)) printf("0"); else { while(l<=r) { mid=(l+r)/2; if(check(mid)) r=mid-1; else l=mid+1; } printf("%d\n",r); } }
浙公网安备 33010602011771号