[HNOI2013]消毒
题目描述
最近在生物实验室工作的小T遇到了大麻烦。 由于实验室最近升级的缘故,他的分格实验皿是一个长方体,其尺寸为a*b*c,a、b、c 均为正整数。为了实验的方便,它被划分为a*b*c个单位立方体区域,每个单位立方体尺寸为1*1*1。用(i,j,k)标识一个单位立方体,1 <=i<=a,1<=j<=b,1<=k<=c。这个实验皿已经很久没有人用了,现在,小T被导师要求将其中一些单位立方体区域进 行消毒操作(每个区域可以被重复消毒)。
而由于严格的实验要求,他被要求使用一种特定 的F试剂来进行消毒。 这种F试剂特别奇怪,每次对尺寸为x*y*z的长方体区域(它由x*y*z个单位立方体组 成)进行消毒时,只需要使用min{x,y,z}单位的F试剂。F试剂的价格不菲,这可难倒了小 T。
现在请你告诉他,最少要用多少单位的F试剂。(注:min{x,y,z}表示x、y、z中的最小 者。)
输入输出格式
输入格式:
第一行是一个正整数D,表示数据组数。接下来是D组数据,每组数据开头是三个数a,b,c表示实验皿的尺寸。接下来会出现a个b 行c列的用空格隔开的01矩阵,0表示对应的单位立方体不要求消毒,1表示对应的单位立方体需要消毒;例如,如果第1个01矩阵的第2行第3列为1,则表示单位立方体(1,2,3)需要被消毒。输入保证满足a*b*c<=5000,T<=3。
输出格式:
仅包含D行,每行一个整数,表示对应实验皿最少要用多少单位 的F试剂。
输入输出样例
1 4 4 4 1 0 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
3
说明
对于区域(1,1,3)-(2,2,4)和(1,1,1)-(4,4,1)消毒,分别花费2个单位和1个单位的F试剂。
题解:
个人认为这道题很强。。。
题目要求的是三维,那么我们先考虑一个简化版的问题,如果是二维的,我们应该怎么做?
不难发现这个简化版的问题是二分图的裸题:
1.将行和列分别虚拟成两列点。
2.将每一个格子虚拟成边连在相对应的行和列上。
3.然后跑一下二分图就好。
但是如果上升成了三维,我们该怎么办?貌似是不存在三分图的。
观察一下数据范围,我们可以发现a*b*c<=5000,这说明a,b,c中至少有一个小于等于17。
于是我们对这最小的一维的状态进行枚举,即当前层是否被全部消毒。这个过程可以用dfs,我用的是循环枚举。
1 //Never forget why you start 2 #include<iostream> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<algorithm> 8 #define inf (2000000000) 9 using namespace std; 10 const int N=5005; 11 int t,cnt,x,y,z; 12 int gi(){ 13 int ans=0,f=1;char i=getchar(); 14 while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();} 15 while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();} 16 return ans*f; 17 } 18 struct point{ 19 int x,y,z; 20 }p[N]; 21 struct node{ 22 int next,to; 23 }edge[N]; 24 int head[N],size=0,vis[N],dfscnt,match[N]; 25 void putin(int from,int to){ 26 size++; 27 edge[size].next=head[from]; 28 edge[size].to=to; 29 head[from]=size; 30 } 31 bool dfs(int r){ 32 int i; 33 for(i=head[r];i!=-1;i=edge[i].next){ 34 int to=edge[i].to; 35 if(vis[to]!=dfscnt){ 36 vis[to]=dfscnt; 37 if(!match[to]||dfs(match[to])){ 38 match[to]=r; 39 return true; 40 } 41 } 42 } 43 return false; 44 } 45 int solve(int s){ 46 int i,ans=0; 47 memset(head,-1,sizeof(head));size=0; 48 memset(match,0,sizeof(match)); 49 for(i=1;i<=cnt;i++)if(!((1<<(p[i].x-1))&s))putin(p[i].y,p[i].z); 50 for(i=1;i<=s;i<<=1)if(i&s)ans++; 51 for(i=1;i<=y;i++){ 52 ++dfscnt; 53 if(dfs(i))ans++; 54 } 55 return ans; 56 } 57 int main(){ 58 int i,j,k,l; 59 t=gi(); 60 while(t--){ 61 x=gi();y=gi();z=gi();cnt=0; 62 for(i=1;i<=x;i++) 63 for(j=1;j<=y;j++) 64 for(k=1;k<=z;k++){ 65 l=gi(); 66 if(l){ 67 p[++cnt].x=i; 68 p[cnt].y=j; 69 p[cnt].z=k; 70 } 71 } 72 if(z<y&&x>z){ 73 swap(x,z); 74 for(i=1;i<=cnt;i++)swap(p[i].x,p[i].z); 75 } 76 if(y<x&&y<z){ 77 swap(x,y); 78 for(i=1;i<=cnt;i++)swap(p[i].x,p[i].y); 79 } 80 int tot=(1<<x)-1,ans=inf; 81 for(i=0;i<=tot;i++)ans=min(ans,solve(i)); 82 printf("%d\n",ans); 83 } 84 return 0; 85 }