bzoj3140: [Hnoi2013]消毒 二分图匹配

来源:互联网 发布:网站源码授权破解 编辑:程序博客网 时间:2024/04/29 12:21

题目链接:戳这里

3140: [Hnoi2013]消毒

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1365  Solved: 598
[Submit][Status][Discuss]

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,未重测.

Source

先喷一波新加数据:我tm被卡常卡成狗了。

分析:此题是个立体问题。

首先可以得出结论:每次消毒肯定是1*b*c,a*1*c,a*b*1的区域,所以问题相当于用多少个面能覆盖掉空间内的所有点。

如果先抽象成一个平面问题:用多少条线能覆盖掉平面内的所有点?那么显然是行列连边做二分图最大匹配了。如果放到空间内该怎么办呢?并没有三分图匹配这种东西。

考虑到a*b*c<=5000,那么a,b,c中最小的值不会超过5000的立方根,即不会超过17(17*17*17=4913)。

那么我们可以先将这个立方体翻转使得a<=b<=c,然后2^a枚举哪些面消毒哪些面不消毒,对于一个消毒的面答案是1,不消毒的面就是这个面上y和z做二分图最大匹配了。

复杂度O(2^17*17*nm)

然后我就这么写了,然后被卡TLE。

这题还有的极大的坑点,不能无脑memset,只能把每次需要用的地方重置,在做二分图匹配的时候可以用一个变量来代替每次memset vis数组。

然后我洛谷过了,bzoj被那两组新加数据继续卡常,f**k。

先上洛谷AC的代码吧,bzoj的应该可以改成非递归的二进制枚举来进一步减小常数。

代码:

#include<bits/stdc++.h>#define maxn 6005#define maxm 60005using namespace std;typedef long long LL;int read(){    char c;int sum=0,f=1;c=getchar();    while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}    while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}    return sum*f;}int T;int a,b,c;int head[maxn],cnt;struct Node{    int nex,to;}edge[maxm];void add(int u,int v){    edge[++cnt].to=v;    edge[cnt].nex=head[u];    head[u]=cnt;}struct point{    int x,y,z;    point(){}    point(int _x,int _y,int _z):x(_x),y(_y),z(_z)    {        if(b<=a&&b<=c) swap(x,y);        else if(c<=a&&c<=b) swap(z,x);    }}p[maxn];int vis[maxn],match[maxn],tot_vis,tot;bool dfs(int x){    for(int i=head[x];i;i=edge[i].nex)    {        int nex=edge[i].to;        if(vis[nex]==tot_vis) continue;        vis[nex]=tot_vis;        if(!match[nex] || dfs(match[nex]))        {            match[nex]=x;            return true;        }    }    return false;}int ans;bool vis_x[maxn];void solve(int pos,int sum){    if(sum>=ans) return;    if(pos>a)    {        for(int i=0;i<=b;i++) head[i]=0,match[i]=0;        cnt=0;        for(int i=1;i<=tot;i++)        if(!vis_x[p[i].x])        add(p[i].y,p[i].z);        for(int i=1;i<=b;i++)        {            tot_vis++;            if(dfs(i)) sum++;            if(sum>=ans) return;        }        ans=sum;        return;    }        vis_x[pos]=1;solve(pos+1,sum+1);    vis_x[pos]=0;solve(pos+1,sum);}int main(){    T=read();    while(T--)    {        tot=0;        a=read();b=read();c=read();        for(int i=1;i<=a;i++)        for(int j=1;j<=b;j++)        for(int k=1;k<=c;k++)        {            int x=read();            if(x)            p[++tot]=point(i,j,k);        }        if(b<=a&&b<=c) swap(a,b);        else if(c<=a&&c<=b) swap(a,c);        ans=a;        solve(1,0);        printf("%d\n",ans);    }    return 0;}

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小便出现浊白色尿液 女性尿液混浊是怎么回事 女性尿液混浊 男性尿液中有白色浑浊物 尿液沉淀后有白色浑浊物 尿血尿脓 小肚子涨老是感觉有尿 尿急尿频尿涨 有尿胀痛 做b超如何快速涨尿 尿涨尿痛 尿痛尿涨 尿涨小腹痛怎么回事 正常尿液颜色 男性尿液有异味是怎么回事 女性尿液突然变黄臭味大 尿液一直是黄的 我的尿液很黄 尿液深黄是怎么回事 白带黄尿液黄 女性尿液黄是什么原因 尿液黄浊 尿液为什么是黄的 尿液泛黄是什么原因 尿液又黄又臭怎么回事 黄绿色尿液是什么原因 尿液一直黄 小便太黄太浓怎么回事 小便非常黄 尿液黄绿 小便黄有泡沫 尿尿很黄怎么回事 小便有点黄 尿尿很黄怎么办 早上起来尿液很黄 尿尿好黄 尿液颜色黄 尿液黄怎么办 尿尿偏黄 尿尿有点黄 尿液又黄又臭