专栏文章
P14219 [ICPC 2024 Kunming I] 阻止城堡 2
P14219题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minlp0m8
- 此快照首次捕获于
- 2025/12/02 04:27 3 个月前
- 此快照最后确认于
- 2025/12/02 04:27 3 个月前
首先删障碍不好考虑,转化为初始没有障碍,要在指定的 个位置加入障碍,要求中间有障碍的城堡对数最大。
发现加入一个障碍最多使得两对城堡产生贡献:横向的一对和纵向的一对。所以我们优先加入能使得两对城堡产生贡献的障碍,再加入能使得一对城堡产生贡献的障碍,最后若还有剩余就随便加入。
将横向相邻的一对城堡看做左部点,纵向相邻的一对城堡看做右部点,那么一个障碍如果能使两对城堡产生贡献,就可以在这两对城堡中连边,我们要求的就是二分图最大匹配。
然后加入能使得一对城堡产生贡献的障碍是简单的,直接模拟即可。
视 同阶,时间复杂度 。
代码
CPP#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<int, int> pii;
const int maxn = 1000100;
const int inf = 0x3f3f3f3f;
int n, m, K, hd[maxn], nt, S, T, len, id1[maxn], id2[maxn], e[maxn];
bool vis[maxn], mk1[maxn], mk2[maxn];
pii c[maxn];
struct node {
int x, y;
} a[maxn], b[maxn];
struct edge {
int to, next, cap, flow;
} edges[maxn << 1];
inline void add_edge(int u, int v, int c, int f) {
edges[++len].to = v;
edges[len].next = hd[u];
edges[len].cap = c;
edges[len].flow = f;
hd[u] = len;
}
struct Dinic {
int cur[maxn], d[maxn];
bool vis[maxn];
inline void add(int u, int v, int c) {
add_edge(u, v, c, 0);
add_edge(v, u, 0, 0);
}
inline bool bfs() {
for (int i = 1; i <= nt; ++i) {
d[i] = -1;
vis[i] = 0;
}
queue<int> q;
q.push(S);
vis[S] = 1;
d[S] = 0;
while (q.size()) {
int u = q.front();
q.pop();
for (int i = hd[u]; i; i = edges[i].next) {
edge &e = edges[i];
if (!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
d[e.to] = d[u] + 1;
q.push(e.to);
}
}
}
return vis[T];
}
int dfs(int u, int a) {
if (u == T || !a) {
return a;
}
int flow = 0, f;
for (int &i = cur[u]; i; i = edges[i].next) {
edge &e = edges[i];
if (d[e.to] == d[u] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
e.flow += f;
edges[i ^ 1].flow -= f;
flow += f;
a -= f;
if (!a) {
break;
}
}
}
return flow;
}
inline int solve() {
int flow = 0;
while (bfs()) {
for (int i = 1; i <= nt; ++i) {
cur[i] = hd[i];
}
flow += dfs(S, inf);
}
return flow;
}
} solver;
void solve() {
len = 1;
for (int i = 0; i <= nt; ++i) {
hd[i] = 0;
}
nt = 0;
scanf("%d%d%d", &n, &m, &K);
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &a[i].x, &a[i].y);
id1[i] = id2[i] = 0;
mk1[i] = mk2[i] = 0;
}
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &b[i].x, &b[i].y);
vis[i] = 0;
}
K = m - K;
map< int, set<pii> > mp1, mp2;
for (int i = 1; i <= n; ++i) {
mp1[a[i].x].emplace(a[i].y, i);
mp2[a[i].y].emplace(a[i].x, i);
}
S = ++nt;
T = ++nt;
int ans = 0;
for (int i = 1; i <= n; ++i) {
auto it = mp1[a[i].x].find(pii(a[i].y, i));
if (next(it) != mp1[a[i].x].end()) {
id1[i] = ++nt;
++ans;
solver.add(S, id1[i], 1);
}
it = mp2[a[i].y].find(pii(a[i].x, i));
if (next(it) != mp2[a[i].y].end()) {
id2[i] = ++nt;
++ans;
solver.add(id2[i], T, 1);
}
}
for (int i = 1; i <= m; ++i) {
e[i] = 0;
c[i] = pii(0, 0);
if (mp1.find(b[i].x) != mp1.end()) {
auto it = mp1[b[i].x].lower_bound(pii(b[i].y, 0));
if (it != mp1[b[i].x].end() && it != mp1[b[i].x].begin()) {
c[i].fst = prev(it)->scd;
}
}
if (mp2.find(b[i].y) != mp2.end()) {
auto it = mp2[b[i].y].lower_bound(pii(b[i].x, 0));
if (it != mp2[b[i].y].end() && it != mp2[b[i].y].begin()) {
c[i].scd = prev(it)->scd;
}
}
int x = c[i].fst, y = c[i].scd;
if (x && y) {
solver.add(id1[x], id2[y], 1);
e[i] = len - 1;
}
}
solver.solve();
int cnt = K;
for (int i = 1; i <= m; ++i) {
if (!e[i]) {
continue;
}
int j = e[i];
if (edges[j].flow) {
if (cnt) {
--cnt;
ans -= 2;
vis[i] = 1;
mk1[c[i].fst] = mk2[c[i].scd] = 1;
}
}
}
for (int i = 1; i <= m; ++i) {
if (vis[i]) {
continue;
}
if (cnt && ((c[i].fst && !mk1[c[i].fst]) || (c[i].scd && !mk2[c[i].scd]))) {
--cnt;
--ans;
vis[i] = 1;
if (c[i].fst) {
mk1[c[i].fst] = 1;
}
if (c[i].scd) {
mk2[c[i].scd] = 1;
}
}
}
for (int i = 1; i <= m; ++i) {
if (!vis[i] && cnt) {
--cnt;
vis[i] = 1;
}
}
printf("%d\n", ans);
for (int i = 1; i <= m; ++i) {
if (vis[i]) {
continue;
}
printf("%d ", i);
}
putchar('\n');
}
int main() {
int T = 1;
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...