bzoj3140 [Hnoi2013]消毒

Description

最近在生物实验室工作的小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中的最小 者。) 

Input

第一行是一个正整数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。

Output

仅包含D行,每行一个整数,表示对应实验皿最少要用多少单位 的F试剂。

Sample Input

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

Sample Output

3

HINT 

对于区域(1,1,3)-(2,2,4)和(1,1,1)-(4,4,1)消毒,分别花费2个单位和1个单位的F试剂。2017.5.26新加两组数据By Leoly,未重测.

 

正解:搜索+二分图匹配。

我们考虑弱化一下条件,假设只有两维,这道题应该怎么做呢?

很显然,我们每次都会选择$[a,m]$或$[n,b]$的矩形进行覆盖,换句话说,我们每次就是覆盖一行或者一列。

那么二维的情况就是二分图最小点覆盖,那么就等于最大匹配,于是我们直接把行向列连边,跑匈牙利就行了。

三维的情况似乎不那么好做了,但是我们注意到$a*b*c\leq 5000$,也就是说,最小的那个数$\leq 17$。

我们可以直接把$c$变成最小值,然后爆搜每一层是否直接消毒,直接消毒代价为$1$。

我们把剩下还没有消毒的层拼在一起,那么它们消毒的代价肯定是行或列。那么我们跑一遍匈牙利就行了。

复杂度$O(2^{c}*a*b)$。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define pos(i,j,k) ((i-1)*b*c+(j-1)*c+k)
 6 
 7 using namespace std;
 8 
 9 int e[5005][5005],vis[5005],lk[5005],sz[5005],d[5005],a,b,c,cnt,ans;
10 
11 il int gi(){
12   RG int x=0,q=1; RG char ch=getchar();
13   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
14   if (ch=='-') q=-1,ch=getchar();
15   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
16   return q*x;
17 }
18 
19 il int dfs(RG int x){
20   for (RG int i=1;i<=c;++i){
21     if (!e[x][i] || vis[i]==cnt) continue; vis[i]=cnt;
22     if (!lk[i] || dfs(lk[i])) return lk[i]=x,1;
23   }
24   return 0;
25 }
26 
27 il void dfs(RG int x,RG int tot){
28   if (x>a){
29     for (RG int i=1;i<=c;++i) vis[i]=lk[i]=0; cnt=0;
30     for (RG int i=1;i<=b;++i) ++cnt,tot+=dfs(i);
31     ans=min(ans,tot); return;
32   }
33   if (tot>=ans) return;
34   for (RG int i=1;i<=b;++i)
35     for (RG int j=1;j<=c;++j) e[i][j]+=d[pos(x,i,j)];
36   dfs(x+1,tot);
37   for (RG int i=1;i<=b;++i)
38     for (RG int j=1;j<=c;++j) e[i][j]-=d[pos(x,i,j)];
39   if (sz[x]) dfs(x+1,tot+1); return;
40 }
41 
42 il void work(){
43   a=gi(),b=gi(),c=gi(),memset(d,0,sizeof(d)),memset(sz,0,sizeof(sz));
44   if (a<=b && a<=c){
45     for (RG int i=1;i<=a;++i)
46       for (RG int j=1;j<=b;++j)
47     for (RG int k=1;k<=c;++k) d[pos(i,j,k)]=gi();
48   } else if (b<=a && b<=c){
49     swap(a,b);
50     for (RG int i=1;i<=b;++i)
51       for (RG int j=1;j<=a;++j)
52     for (RG int k=1;k<=c;++k) d[pos(j,i,k)]=gi();
53   } else{
54     swap(a,c);
55     for (RG int i=1;i<=c;++i)
56       for (RG int j=1;j<=b;++j)
57     for (RG int k=1;k<=a;++k) d[pos(k,j,i)]=gi();
58   }
59   for (RG int i=1;i<=a;++i)
60     for (RG int j=1;j<=b;++j)
61       for (RG int k=1;k<=c;++k) sz[i]+=d[pos(i,j,k)];
62   ans=1<<30,dfs(1,0),printf("%d\n",ans); return;
63 }
64 
65 int main(){
66 #ifndef ONLINE_JUDGE
67   freopen("clear.in","r",stdin);
68   freopen("clear.out","w",stdout);
69 #endif
70   RG int T=gi();
71   while (T--) work();
72   return 0;
73 }

 

posted @ 2017-12-02 10:30  wfj_2048  阅读(305)  评论(0编辑  收藏  举报