先考虑一个平面上的问题:
平面上有
n
个点,消除一个
在这里,我们可以发现,在这里用
min(x,y)
条竖线或横线就可以覆盖一个
x∗y
的矩形。这样就变成了二分图最小点覆盖的裸题,套模板即可。
回到问题。同样也可以将问题理解为以下模型:
空间内有
n
个点,每一次操作可以消除一个面上所有的点,求消除所有点的最少操作次数。
但是这是三维的,所以不能简单地求最小点覆盖。怎么做呢?
看到题目中有
同时注意:此题时限卡得较紧,请注意一些常数优化。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 5005, E = 23, INF = 0x3f3f3f3f;
int n, D[5], pos, ecnt, nxt[N], adj[N], go[N], val[N], my[N],
X[N][5], Ans, cnt, vis[N], times;
bool sel[E];
void add_edge(int u, int v, int w) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;
}
bool dfs(int u) {
for (int e = adj[u], v; e; e = nxt[e])
if (!sel[val[e]] && vis[v = go[e]] < times) {
vis[v] = times;
if (!my[v] || dfs(my[v])) {
my[v] = u;
return 1;
}
}
return 0;
}
int solve(int tt) {
int i, j, ans = 0;
for (i = 1; i <= cnt; i++) my[i] = 0;
for (i = 1; i <= cnt; i++) {
times++;
if (dfs(i)) ans++;
if (tt + ans >= Ans) return tt + ans;
}
return tt + ans;
}
void Dfs(int dep, int tt) {
if (dep > D[pos]) return (void) (Ans = min(Ans, solve(tt)));
sel[dep] = 1; Dfs(dep + 1, tt + 1);
sel[dep] = 0; Dfs(dep + 1, tt);
}
void work() {
int i, j, k, x; n = 0; Ans = INF; cnt = 0;
pos = 1; D[1] = read(); D[2] = read(); D[3] = read();
if (D[2] < D[pos]) pos = 2; if (D[3] < D[pos]) pos = 3;
for (i = 1; i <= 3; i++) if (i != pos) cnt = max(cnt, D[i]);
for (i = 1; i <= D[1]; i++) for (j = 1; j <= D[2]; j++)
for (k = 1; k <= D[3]; k++) {
x = read(); if (x) X[++n][1] = i, X[n][2] = j, X[n][3] = k;
}
ecnt = 0; for (i = 1; i <= cnt; i++) adj[i] = 0;
for (i = 1; i <= n; i++) {
if (pos == 1) add_edge(X[i][2], X[i][3], X[i][1]);
else if (pos == 2) add_edge(X[i][1], X[i][3], X[i][2]);
else add_edge(X[i][1], X[i][2], X[i][3]);
}
printf("%d\n", (Dfs(1, 0), Ans));
}
int main() {
int T = read();
while (T--) work();
return 0;
}