[题解] BZOJ 3140 [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 个单位立方体组成)进行消毒时,只需要使用 m i n x , y , z 单位的F试剂。F试剂的价格不菲,这可难倒了小T。现在请你告诉他,最少要用多少单位的F试剂。(注: m i n x , y , z 表示 x , y , z 中的最小者。)

输入描述 Input Description
第一行是一个正整数 D ,表示数据组数。
接下来是 D 组数据,每组数据开头是三个数 a , b , c 表示实验皿的尺寸。接下来会出现 a b c 列的用空格隔开的01矩阵,0表示对应的单位立方体不要求消毒,1表示对应的单位立方体需要消毒;例如,如果第1个01矩阵的第2行第3列为1,则表示单位立方体(1,2,3)需要被消毒。

输出描述 Output Description
仅包含 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

样例解释
对于区域(1,1,3)-(2,2,4)和(1,1,1)-(4,4,1)消毒,分别花费2个单位和1个单位的F试剂。

数据范围及提示 Data Size & Hint
输入保证满足 a b c 5000 , T 3

Solution

强烈安利二维简单版
[POJ3041]Asteroids

首先考虑二维的情况

显然每次覆盖都是选择横向的一排或者纵向的一列才是最优的
那么每个点会被一个横向的一排覆盖或者纵向的一列覆盖(或者两者皆有?)
那么,转化为二分图最小点覆盖问题,将横坐标作为一侧的节点,将纵坐标作为另外一侧的节点,对于每一个点 ( x , y ) ,将左侧的x节点和右侧y节点连接起来.这样,问题就变为了怎么让每一条边两端至少有一边被覆盖,即二分图最小点覆盖问题

emm,如果你还记得的话,最小点覆盖就是二分图的最大匹配数,不会的话记得复习二分图&网络流哦

所以直接跑匈牙利就好了

那么三维呢?

首先,可以看到数据范围中 a b c 5000 ,显然 m i n ( a , b , c ) 5000 3 17
那么可以枚举最小的一维然后强行将其转化为二维情况
枚举最小的一维中0为直接将这一层全部消毒,1为这一层暂时不消毒
然后把剩下的那些没有消毒的层放在一起,全部压到一张图上,二分图匹配即可

代码如下

#include <bits/stdc++.h>
using namespace std;
#define N 5005
#define lowbit(x) ((x)&(-(x)))
struct edge {
    int to;
    int next;
}e[N*10];
struct C {
    int i;
    int j;
    int k;
}c[N];
int head[N],tot;
int my[N],use[N],have[N];
int x,y,z,s,cnt,times;
int read() {
    int ans=0,flag=1;
    char ch=getchar();
    while((ch>'9' || ch<'0') && ch!='-') ch=getchar();
    if(ch=='-') flag=-1,ch=getchar();
    while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
    return ans*flag;
}
int get(int x) {
    int ans=0;
    while(x) {
        x-=lowbit(x);
        ans++;
    }
    return ans;
}
void addedge(int u,int v) {
    e[++tot].to=v;
    e[tot].next=head[u];
    head[u]=tot;
}
bool dfs(int x) {
    for(int i=head[x];i;i=e[i].next) {
        int to=e[i].to;
        if(use[to]!=times) {
            use[to]=times;
            if(!my[to] || dfs(my[to])) {
                my[to]=x;
                return true;
            }
        }
    }
    return false;
}
int main() {
    int T=read();
    while(T--) {
        cnt=0;
        x=read();y=read();z=read();
        for(int i=1;i<=x*y*z;i++) have[i]=0;
        if(x<=y && x<=z) s=1;
        else if(y<=x && y<=z) s=2;
        else s=3;
        for(int i=1;i<=x;i++)
            for(int j=1;j<=y;j++)
                for(int k=1;k<=z;k++) {
                    int r=read();
                    if(r) {
                        cnt++;
                        if(s==1) {c[cnt].i=i;c[cnt].j=j;c[cnt].k=k;}
                        else if(s==2) {c[cnt].i=j;c[cnt].j=i;c[cnt].k=k;}
                        else {c[cnt].i=k;c[cnt].j=i;c[cnt].k=j;}
                        have[c[cnt].i]=1;
                    }
                }
        if(s==2) {swap(x,y);}
        if(s==3) {swap(x,y);swap(y,z);}
        int ans=x;
        for(int now=0;now<(1<<x);now++) {
            tot=0;
            int num=get(now);
            bool flag=0;
            for(int i=0;i<x;i++) {
                if(((1<<i)&now) && (!have[i+1])) {
                    flag=1;
                    break;
                }
            }
            if(flag) continue;
            for(int i=1;i<=y;i++) head[i]=0;
            for(int i=1;i<=cnt;i++) {
                if(1<<(c[i].i-1)&now) continue;
                addedge(c[i].j,c[i].k);
            }
            for(int i=1;i<=z;i++) my[i]=0;
            for(int i=1;i<=y;i++) {
                if(head[i]) {
                    times++;
                    if(dfs(i)) num++;
                    if(num>=ans) break;
                }
            }
            if(num<ans) ans=num;
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/force_chl/article/details/79673210