P3231 [HNOI2013]消毒

P3231 [HNOI2013]消毒

二维覆盖我们已经很熟悉了

扩展到三维,枚举其中较小的一维,这里定义为$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;
}

  

原文地址:https://www.cnblogs.com/y2823774827y/p/10123612.html