二维覆盖我们已经很熟悉了
扩展到三维,枚举其中较小的一维,这里定义为$a$
以$a$为关键字状压,$1$表示该面全选
剩下的面和二维覆盖一样二分图匹配
如果还没接触过二维覆盖,简要地说一下
代价是$min(x,y)$,假设$x$比$y$小,全染相当于染$x$次$1×y$的区域,故全染不如一条一条染
My complete code:
#include<cstdio> #include<cstring> #include<string> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; const LL inf=0x3f3f3f3f; const LL maxn=6000; inline LL Read(){ LL x=0,f=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); }return x*f; } struct node{ LL to,next; }dis[6000000]; LL a,b,c,T,num,cnt,ans,minn,up; LL head[maxn],visit[maxn],mat[maxn],que[4][maxn]; bool piece[maxn]; inline void Add(LL u,LL v){ dis[++num]=(node){v,head[u]}; head[u]=num; } bool Dfs(LL u,LL val){ for(LL i=head[u];i;i=dis[i].next){ LL v=dis[i].to; if(visit[v]!=val){ visit[v]=val; if(!mat[v]){ mat[v]=u; return true; }else if(Dfs(mat[v],val)){ mat[v]=u; return true; } } } return false; } inline void Solve(LL bit){ LL sum=0; for(LL i=1;i<=a;++i) if((bit>>(i-1))&1){ piece[i]=false, ++sum; }else piece[i]=true; num=0; for(LL i=1;i<=b;++i) head[i]=0; for(LL i=1;i<=cnt;++i) if(piece[que[1][i]]) Add(que[2][i],que[3][i]); for(LL i=1;i<=c;++i) mat[i]=0, visit[i]=0; for(LL i=1;i<=b;++i) if(Dfs(i,i)) ++sum; ans=min(ans,sum); } int main(){ T=Read(); while(T--){ cnt=0; a=Read(),b=Read(),c=Read(); for(LL i=1;i<=a;++i) for(LL j=1;j<=b;++j) for(LL k=1;k<=c;++k) if(Read()){ que[1][++cnt]=i, que[2][cnt]=j, que[3][cnt]=k; } minn=min(a,min(b,c)); if(minn==b){ swap(a,b); swap(que[1],que[2]); }else if(minn==c){ swap(a,c); swap(que[1],que[3]); } up=(1<<a); ans=inf; for(LL i=0;i<up;++i) Solve(i); printf("%lld ",ans); } return 0; }