洛谷 P1525 关押罪犯 (贪心,扩展域并查集)
-
题意:有\(n\)个罪犯,\(m\)对罪犯之间有仇,现在将这些罪犯分到两个监狱里去,问两个监狱里有仇罪犯之间的最大权值最小为多少.
-
题解:先按边权从大到小排序,然后贪心,边权大的两个罪犯,我们一定要先让他们两人分到不同的监狱中,这里我们就可以用并查集来维护, 用种类并查集每次维护两个罪犯的关系,如果他们不在同一集合,就将他们合并到两个不同的集合,
如果他们在同一个集合,那么就直接输出他们的权值.
-
代码:
#include <iostream> #include <iomanip> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <stack> #include <queue> #include <vector> #include <map> #include <set> #include <unordered_set> #include <unordered_map> #define ll long long #define db double #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; int gcd(int a,int b){return b?gcd(b,a%b):a;} int lcm(int a,int b){return a/gcd(a,b)*b;} inline int read() { int X=0; bool flag=1; char ch=getchar(); while(ch<'0'|ch>'9') {if(ch=='-') flag=0; ch=getchar();} while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();} if(flag) return X; return ~(X-1); } struct misaka{ int x,y,val; bool operator < (const misaka & mikoto) const{ return val>mikoto.val; } }e[N]; int n,m; int p[N]; int find(int x){ if(p[x]!=x) p[x]=find(p[x]); return p[x]; } int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n>>m; rep(i,1,m){ cin>>e[i].x>>e[i].y>>e[i].val; } sort(e+1,e+1+m); rep(i,1,2*n+10) p[i]=i; rep(i,1,m){ int x=e[i].x; int y=e[i].y; if(p[find(x)]==p[find(y)] || p[find(x+n)]==p[find(y+n)]){ cout<<e[i].val<<'\n'; return 0; } p[find(x)]=p[find(y+n)]; p[find(x+n)]=p[find(y)]; } cout<<0<<'\n'; return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮