BZOJ3140:[HNOI2013]消毒——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=3140

https://www.luogu.org/problemnew/show/P3231

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

参考:洛谷两个题解。

论算法很简单,但是思路真不好想。

首先对于二维来讲,最优的策略就是每次消毒一行/列。

那么对于三维同样适用。

二维的解题思路可以参考:POJ3041:Asteroids

但是现在是三维的怎么办?拍成二维的即可。

我们发现一定有min(a,b,c)<=17,于是我们可以令a<=17,这样我们枚举一维a是否被去除,然后将剩下的拍扁成二维做即可。

(PS:bzoj卡常,这个代码也只是刚好卡过。)

#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5050;
struct node{
    int to,nxt;
}e[N];
int cnt,t,a,b,c,ans,shu[N],head[N],vis[N];
int mp[4][N],tot,res;
bool ok[N];
inline void add(int u,int v){
    e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
bool dfs(int u,int id){
    for(int i=head[u];i;i=e[i].nxt){
    int v=e[i].to;
    if(vis[v]!=id){
        vis[v]=id;
            if(!shu[v]||dfs(shu[v],id)){
                shu[v]=u;
                return 1;
            }
    }
    }
    return 0;
}
void solve(int x){
    for(int i=1;i<=b;i++)head[i]=0;
    for(int i=1;i<=c;i++)vis[i]=shu[i]=0;
    cnt=res=0;
    for(int i=0;i<a;i++){
    if(x&(1<<i)){
        ok[i+1]=0;
        res++;
        if(res>=ans)return;
    }
    else ok[i+1]=1;
    }
    for(int i=1;i<=tot;i++){
    if(ok[mp[1][i]])
        add(mp[2][i],mp[3][i]);
    }
    for(int i=1;i<=b;i++){
    if(dfs(i,i))res++;
    if(res>=ans)return;
    }
    ans=res;
}
int main(){
    scanf("%d",&t);
    while(t--){
    tot=0;ans=2147483647;
    scanf("%d%d%d",&a,&b,&c);
    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
        for(int k=1;k<=c;k++){
            int x;scanf("%d",&x);
            if(x){
            mp[1][++tot]=i;
            mp[2][tot]=j;
            mp[3][tot]=k;
            }
        }
        }
    }
    int minn=min(a,min(b,c));
    if(minn==b)swap(a,b),swap(mp[1],mp[2]);
    else if(minn==c)swap(a,c),swap(mp[1],mp[3]);
    for(int i=0;i<(1<<a);i++)
        solve(i);
    printf("%d\n",ans);
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-03-11 11:54  luyouqi233  阅读(203)  评论(0编辑  收藏  举报