日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CH - 4901 关押罪犯(二分图判定+二分/并查集)

發布時間:2024/4/11 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 关押罪犯(二分图判定+二分/并查集)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。