标签:head 无法 集合 颜色 细节 ges ++ ring int
这道题有两种解法。
第一种是并查集补集,就是开两倍并查集空间,要隔离,就把一人的原集和另一个人的补集合并。
从大到小排序,直到无法合并的时候就输出,这个时候就是答案。
我之前做(chao)过,这里就不写了。
第二种是二分答案+二分图判定。
显然,答案希望是越来越小,因为被隔离的人会更多。
但是可能会冲突,即不满足两个监狱。需要更多的监狱来装他们。
把这些人隔离在两个监狱,就是把点隔离在两个集合里面。
这个东西就是二分图的模型。
只有那些矛盾值大于答案的,才需要隔离,才有边。
所以在这个基础上,进行二分图判定(染色法),确实是二分图就是一个可行解。
这里讲一下二分图判定的一个小细节:
这个二分图不一定连通。所以每次找到点color为0时就从这个点开始染色。确保整个图都染了。
当两边颜色一样的时候直接return false。
二分的时候有点小操作,自己领悟去吧。。。
然后就可以了。
代码:
#include<cstdio>
#include<cstring>
#include<queue>
const int maxn = 20005, maxm = 100005;
struct Edges
{
int next, to, weight;
} e[maxm << 1];
int head[maxn], tot;
int n, m;
int color[maxn];
void link(int u, int v, int w)
{
e[++tot] = (Edges){head[u], v, w};
head[u] = tot;
}
bool check(int mid)
{
memset(color, 0, sizeof color);
std::queue<int> q;
for(int x = 1; x <= n; x++)
{
if(color[x] == 0)
{
color[x] = 1; q.push(x);
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
if(e[i].weight <= mid) continue;
if(color[v] == color[u]) return false;
else if(color[v] == 0)
{
color[v] = 3 - color[u];
q.push(v);
}
}
}
}
}
return true;
}
int main()
{
scanf("%d%d", &n, &m);
while(m--)
{
int u, v, w; scanf("%d%d%d", &u, &v, &w);
link(u, v, w); link(v, u, w);
}
int left = 0, right = 1000000005, ans = 0;
while(left <= right)
{
int mid = (left + right) / 2;
if(check(mid)) ans = mid, right = mid - 1;
else left = mid + 1;
}
printf("%d\n", ans);
return 0;
}
标签:head 无法 集合 颜色 细节 ges ++ ring int
原文地址:https://www.cnblogs.com/Garen-Wang/p/9780922.html