CH - 4901 关押罪犯(二分图判定+二分/并查集)
生活随笔
收集整理的這篇文章主要介紹了
CH - 4901 关押罪犯(二分图判定+二分/并查集)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接:點擊查看
題目大意:一共有n個罪犯,有m對仇人,每對仇人都有一個仇恨值,如果兩個仇人在一起的話,會對監獄造成等價于仇恨值的損失,現在有兩個監獄,可以將罪犯們分開關押,問監獄的最小損失是多少
題目分析:每對仇人之間都可以建邊,這樣就可以直接二分答案,然后每一次都重新建邊,若邊權小于等于當前二分的mid,則忽略該邊,若邊權大于當前二分的mid,則加入到圖中,最后判斷一下當前的圖能否構成二分圖即可,若當前的圖可以構成二分圖,則當前答案有效,否則當前答案偏小了,需要增加mid,因為邊給的比較少,所以時間復雜度時m*logn,雖然有點小暴力,但并不會超時
2020.11.2更新:
之前偷懶沒有用并查集做,然后打 cf 的時候碰到了一個相似的知識點,然后就木得了
利用并查集維護二分圖的染色問題,首先給每個點建立一個對應的虛點 i + n,假設點 i 在集合 1 中,那么點 i + 1 必定在集合 2 中,反之亦然。
此時假設存在二分圖的一條邊 ( x , y ) ,其意義就是 x 和 y 不能在同一個集合中,換句話說,x 一定和 y + n 在同一個集合中,同理 y 也一定和 x + n 在同一個集合中,如果 x 和 y 存在于同一個集合中就說明當前這條邊會與之前的邊組成奇環,所以不符合題意
代碼:
dfs+二分
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2e4+100;int n,m;vector<int>node[N];int color[N];struct Edge {int u,v,w; }edge[N*5];void init() {for(int i=1;i<=n;i++){node[i].clear();color[i]=-1;} }bool dfs(int u,int c)//二分圖的染色法判定 {color[u]=c;for(int i=0;i<node[u].size();i++){int v=node[u][i];if(color[v]==-1&&!dfs(v,!c))return false;else if(color[v]==c)return false;}return true; }bool check(int x) {init();for(int i=1;i<=m;i++)//重新建邊{if(edge[i].w<=x)continue;int u=edge[i].u;int v=edge[i].v;node[u].push_back(v);node[v].push_back(u);}for(int i=1;i<=n;i++)//二分圖的判定if(color[i]==-1)if(!dfs(i,0))return false;return true; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++)scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);int l=0,r=inf;int ans=0;while(l<=r)//二分答案{int mid=l+r>>1;if(check(mid)){ans=mid;r=mid-1;}elsel=mid+1;}printf("%d\n",ans);return 0; }并查集
//#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;struct Node {int u,v,w;void input(){scanf("%d%d%d",&u,&v,&w);}bool operator<(const Node& t)const{return w>t.w;} }edge[N];int f[N];int find(int x) {return f[x]==x?x:f[x]=find(f[x]); }void merge(int x,int y) {int xx=find(x),yy=find(y);f[xx]=yy; }void init() {for(int i=0;i<N;i++)f[i]=i; }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=m;i++)edge[i].input();sort(edge+1,edge+1+m);for(int i=1;i<=m;i++){int x=edge[i].u,y=edge[i].v;int xx=find(x),yy=find(y);if(xx==yy)return 0*printf("%d\n",edge[i].w);elsemerge(x,y+n),merge(y,x+n);}puts("0");return 0; }?
總結
以上是生活随笔為你收集整理的CH - 4901 关押罪犯(二分图判定+二分/并查集)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ - 2226 Muddy Fie
- 下一篇: CH - 6801 棋盘覆盖(二分图最大