關押罪犯
阿新 • • 發佈:2021-06-10
題目:
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); } }