消毒
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,未重测.
特技网络流…..
不会加特技的蒟蒻瑟瑟发抖……
思路:
首先有个很明显的结论:
对于一次消毒,其效果等价于将产生贡献的那一维分割成若干长度仅为1的切片的效果。
这个结论的正确性是显然的~
如果这是二维,那么把两维作为二分图的两边,每个需要消毒的区域作为边连接两维,然后就是裸的最小点覆盖了~
然而这题有三维……
作为蒟蒻,咱就卡在了这里。
然而,注意到
a∗b∗c≤5000
,那么根据均值不等式,必有一维的值小于
17
。
于是把最小的一维单独提出来,对这一维进行状压爆搜所有选取方案,对于每种方案对另两维建二分图跑最小点覆盖计算额外贡献,最后取最值即可~
这令人窒息的操作……
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
const int N=5009;
int a,b,c,s,t,pts;
namespace flow
{
const int M=N<<1;
const int P=N<<1;
int to[M],nxt[M],w[M],beg[P],tot=1;
int dis[M],q[M];
inline void init()
{
memset(beg,0,sizeof(beg[0])*(pts+9));
tot=1;
}
inline void adde(int u,int v,int c)
{
to[++tot]=v;
nxt[tot]=beg[u];
w[tot]=c;
beg[u]=tot;
}
inline void add(int u,int v,int c)
{
adde(u,v,c);adde(v,u,0);
}
inline bool bfs()
{
memset(dis,-1,sizeof(dis[0])*(pts+5));
q[1]=s;dis[s]=0;
for(int l=1,r=1,u=q[l];l<=r;u=q[++l])
for(int i=beg[u];i;i=nxt[i])
if(w[i]>0 && !(~dis[to[i]]))
dis[to[i]]=dis[u]+1,q[++r]=to[i];
return ~dis[t];
}
inline int dfs(int u,int flow)
{
if(u==t || !flow)return flow;
int cost=0;
for(int i=beg[u],f;i;i=nxt[i])
if(w[i]>0 && dis[to[i]]==dis[u]+1)
{
f=dfs(to[i],min(flow-cost,w[i]));
w[i]-=f;w[i^1]+=f;cost+=f;
if(cost==flow)break;
}
if(!cost)dis[u]=-1;
return cost;
}
inline int dinic()
{
int ret=0;
while(bfs())
ret+=dfs(s,1e9);
return ret;
}
}
typedef pair<int,int> pr;
vector<pr> vec[19];
int mina()
{
a=read();b=read();c=read();
for(int i=0;i<19;i++)
vec[i].clear();
int mv=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++)
{
if(read()==1)
{
if(mv==a)
vec[i].push_back(pr(j,k));
else if(mv==b)
vec[j].push_back(pr(i,k));
else
vec[k].push_back(pr(j,i));
}
}
if(mv==b)swap(a,b);
else if(mv==c)swap(a,c);
int mx=1<<a,ans=1e9+7;
s=b+c+1;t=b+c+2;pts=b+c+3;
for(int i=0;i<mx;i++)
{
flow::init();
for(int j=1;j<=b;j++)
flow::add(s,j,1);
for(int j=1;j<=c;j++)
flow::add(j+b,t,1);
int cans=0;
for(int j=1;j<=a;j++)
if(!(i>>(j-1)&1))
for(int k=0;k<vec[j].size();k++)
flow::add(vec[j][k].first,vec[j][k].second+b,1e9+7);
else
cans++;
cans+=flow::dinic();
ans=min(ans,cans);
}
printf("%d\n",ans);
return 0;
}
int main()
{
for(int T=read();T;T--)
mina();
return 0;
}