[Hnoi2013]消毒
显然选择的区域有一维要是1,其他维要最大
相当于问最少切多少个面才能覆盖所有点
a*b*c<=5000
那么一定有一个小于等于17
枚举这一维切不切,跑二分图即可
TLE代码千万别复制
# include <bits/stdc++.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
# define Copy(a, b) memcpy(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(5010), __(1e6 + 10);
IL ll Read(){
RG char c = getchar(); RG ll x = 0, z = 1;
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int a, b, c, x[_], y[_], z[_], n, ans;
int fst[_], nxt[__], to[__], cnt, match[_], vis[_], id;
IL void Add(RG int u, RG int v){ to[cnt] = v; nxt[cnt] = fst[u]; fst[u] = cnt++; }
IL bool Dfs(RG int u){
for(RG int e = fst[u]; e != -1; e = nxt[e]){
if(vis[to[e]] == id) continue;
vis[to[e]] = id;
if(match[to[e]] == -1 || Dfs(match[to[e]])){
match[to[e]] = u;
return 1;
}
}
return 0;
}
IL int Calc(RG int S){
Fill(fst, -1); cnt = 0; Fill(match, -1);
for(RG int i = 1; i <= n; ++i) if(S & (1 << (z[i] - 1))) Add(x[i], y[i]);
RG int Ans = c;
for(; S; S -= S & -S) --Ans;
for(RG int i = 1; i <= a; ++i) ++id, Ans += Dfs(i);
return Ans;
}
int main(RG int argc, RG char* argv[]){
RG int T = Read();
while(T--){
n = 0; a = Read(); b = Read(); c = Read();
for(RG int i = 1; i <= a; ++i)
for(RG int j = 1; j <= b; ++j)
for(RG int k = 1; k <= c; ++k)
if(Read()) x[++n] = i, y[n] = j, z[n] = k;
if(a < b && a < c){
swap(a, c);
for(RG int i = 1; i <= n; ++i) swap(x[i], z[i]);
}
else if(b < a && b < c){
swap(b, c);
for(RG int i = 1; i <= n; ++i) swap(y[i], z[i]);
}
ans = c;
for(RG int i = 0, S = 1 << c; i < S; ++i) ans = min(ans, Calc(i));
printf("%d\n", ans);
}
return 0;
}