Solution
先考虑二维
对于一个点 ((x,y)) ,要么是在第 (x) 列被消毒,要么是在第 (y) 列被消毒,考虑二分图匹配,左边是列,右边是行,求最小点覆盖即可。
回到三维
显然三分图匹配是不可的,所以要看看别的东西。
题目中给了 (abcleq 5000) ,也就是 (min{a,b,c}leq sqrt[3] {5000}approx 17) ,所以可以枚举最小的一维,判断是将一层全部消掉还是留下,然后再将剩下的拍成一个二维平面(或者说,将枚举的那一位坐标去掉),按上面二维方法求解即可。
Code
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
struct lsqy{
int next,to;
}q[5010];
int a,b,c,ys[5101];
int dir[4][5101],tot;
int match[5001],vis[5100],head[5101],cnt;
int ans=2147483644;
void add(int x,int y)
{
q[++cnt].next=head[x];
head[x]=cnt;
q[cnt].to=y;
}
bool dfs(int u)
{
for(int i=head[u];i;i=q[i].next)
{
int v=q[i].to;
if(!vis[v])
{
vis[v]=1;
if(dfs(match[v])||!match[v])
{
match[v]=u;
return 1;
}
}
}
return 0;
}
void work(int s)
{
for(int i=1;i<=b;++i)
head[i]=0;
for(int j=1;j<=c;++j)
match[j]=0;
cnt=0;
int con=0;
//memset(ys,0,sizeof(ys));
for(int i=1;i<=a;++i)
if((1<<(i-1))&s) ys[i]=0,con++;
else ys[i]=1;
for(int i=1;i<=tot;++i)
if(ys[dir[1][i]])
add(dir[2][i],dir[3][i]);
for(int i=1;i<=b;++i)
{
for(int j=1;j<=c;++j)
vis[j]=0;
//memset(vis,0,sizeof(vis));
if(dfs(i)) con++;
}
ans=min(ans,con);
}
int main()
{
int T_T,minn;
scanf("%d",&T_T);
while(T_T--)
{
tot=0;
minn=ans=2147483644;
scanf("%d%d%d",&a,&b,&c);
minn=min(a,min(b,c));
for(int i=1;i<=a;++i)
for(int j=1;j<=b;++j)
for(int k=1;k<=c;++k)
{
int x;
scanf("%d",&x);
if(!x) continue;
tot++;
dir[1][tot]=i;
dir[2][tot]=j;
dir[3][tot]=k;
}
if(minn=b) swap(b,a),swap(dir[1],dir[2]);
else if(minn=c) swap(c,a),swap(dir[1],dir[3]);
for(int i=0;i<=(1<<a)-1;++i)
work(i);
printf("%d
",ans);
}
}
感谢bored的精彩代码