AcWing257 关押罪犯
题目大意
正权无向图
,定义冲突值为一个集合内权值最大的边
,将一张图上的点,分成两部分,不同部分的点在原图上的边作废,求最小化最大
冲突值,并输出。
解题思路
1. 二分答案 + 二分图判定
最小化最大冲突值
,遇到最大值最小化的问题,经验上可以采用二分答案
求解,具体步骤就是二分出这个最大冲突值,要使一个冲突值合法,应该有如下性质;
二分图
即可,如果是二分图,代表满足
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
采用的是染色法判定二分图,模板如下
bool dfs(int cur, int c, int mid)
{
clr[cur] = c;
for (int i = h[cur]; ~i; i = ne[i])
{
int j = e[i];
if (w[i] <= mid) continue ;
if (clr[j] && clr[j] == c) return false;
if (!clr[j] && !dfs(j, 3 - c, mid)) return false;
}
return true ;
}
完整AC代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e6 + 10;
int h[N], e[N], ne[N], w[N], idx;
int clr[N], u, v, c, n, m;
void add(int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}
bool dfs(int cur, int c, int mid)
{
clr[cur] = c;
for (int i = h[cur]; ~i; i = ne[i])
{
int j = e[i];
if (w[i] <= mid) continue ;
if (clr[j] && clr[j] == c) return false;
if (!clr[j] && !dfs(j, 3 - c, mid)) return false;
}
return true ;
}
bool check(int mid)
{
memset(clr, 0, sizeof clr);
for (int i = 1; i <= n; i ++ )
if (!clr[i]) if (!dfs(i, 1, mid))
return false;
return true ;
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while (m -- )
{
scanf("%d%d%d", &u, &v, &c);
add(u, v, c), add(v, u, c);
}
int l = 0, r = 1e9;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", r);
return 0;
}
扩展域并查集
敌人的敌人是朋友
,所以我们可以想到有并查集
来维护,遇到上述边
完整AC代码
#include <iostream>
using namespace std;
const int N = 2e5 + 10;
int n, m, p[N << 1];
struct Edge
{
int u, v, w;
} edge[1000010];
int find(int x)
{
if (x == p[x]) return x;
return p[x] = find(p[x]);
}
bool check(int mid)
{
for (int i = 1; i <= N << 1; i ++ ) p[i] = i;
for (int i = 1; i <= m; i ++ )
{
if (edge[i].w > mid)
{
int pa = find(edge[i].u), pb = find(edge[i].v);
if (pa == pb) return false;
p[pa] = find(edge[i].v + n);
p[pb] = find(edge[i].u + n);
}
}
return true ;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i ++ )
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[i] = {u, v, w};
}
int l = 0, r = 1e9;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", r);
return 0;
}
带边权并查集
判断的时候对于同一个集合里面的元素,如果边权和
完整AC代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 2e5 + 10;
int n, m, p[N], d[N];
struct Edge
{
int u, v, w;
} edge[1000100];
int find(int x)
{
if (x == p[x]) return x;
int root = find(p[x]);
d[x] ^= d[p[x]], p[x] = root;
return p[x];
}
bool check(int mid)
{
memset(d, 0, sizeof d);
for (int i = 1; i <= n; i ++ ) p[i] = i;
for (int i = 1; i <= m; i ++ )
{
if (edge[i].w > mid)
{
int x = edge[i].u, y = edge[i].v;
int px = find(x), py = find(y);
if (px == py)
if (d[x] ^ d[y] == 0) return false;
if (px != py)
d[px] = d[x] ^ d[y] ^ 1, p[px] = py;
}
}
return true ;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i ++ )
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[i] = {u, v, w};
}
int l = 0, r = 1e9;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", r);
return 0;
}
算法对比
时间:带边权
代码复杂度:扩展域
思维复杂度:扩展域
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业