其他分享
首页 > 其他分享> > P3231 [HNOI2013]消毒

P3231 [HNOI2013]消毒

作者:互联网

文章目录

R e s u l t Result Result

...


H y p e r l i n k Hyperlink Hyperlink

https://www.luogu.com.cn/problem/P3231


D e s c r i p t i o n Description Description

一个 a × b × c a\times b\times c a×b×c的三维立方体内有若干个点,你每次可以选择一个大小为 x × y × z x\times y\times z x×y×z的矩阵进行清除,可以将这个矩阵内所有的点删除,花费 m i n { x , y , z } min\{x,y,z\} min{x,y,z}的代价,问删除所有点的最少代价

数据范围: a × b × c ≤ 5 × 1 0 3 a\times b\times c\leq 5\times 10^3 a×b×c≤5×103


S o l u t i o n Solution Solution

首先,我们肯定是每次删除一个面,这样肯定是最优的(仔细想想为什么)
又因为 3 5000 < 18 _3\sqrt{5000}< 18 3​5000 ​<18,说明 a , b , c a,b,c a,b,c当中至少有一个小于18,
自然我们令 a a a是最小的,只需要 2 a 2^a 2a枚举每个面是否直接删掉,如果不删掉,则把这些面压扁转换成平面的情况

转换成平面的情况后,问题就变成了 b × c b\times c b×c的平面上有若干个点,每次可以选择删除一行/列,问最少删除多少次

显然是个最大匹配问题,用匈牙利算法即可

时间复杂度: O ( 2 a × b 2 × c 2 ) O(2^a\times b^2\times c^2) O(2a×b2×c2)


C o d e Code Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 5010
#define M 5010
#define LL long long
using namespace std;
struct node{int next,to;}edge[M];bool vis[N];int tot,l[N],link[N];
void add(int u,int v){edge[++tot].to=v;edge[tot].next=l[u];l[u]=tot;return;}
inline LL read()
{
    char c;LL f=0,d=1;
    while((c=getchar())<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
    while((c=getchar())>=48&&c<=57)f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
inline int find(int p)
{
    for(int i=l[p];i;i=edge[i].next)
     if(!vis[edge[i].to])
    {
        vis[edge[i].to]=1;
        int q=link[edge[i].to];
        link[edge[i].to]=p;
        if(!q||find(q)) return true;
        link[edge[i].to]=q;
    }
    return false;
}
int T,a,b,c,minn,p[3][N],cnt,x,ans;
bool flg[N];
inline void work(int x)
{
	int now=0,tmp=0;
	for(register int i=1;i<=a;i++) flg[i]=(x>>(i-1))&1,tmp+=(x>>(i-1))&1;
	fill(l+1,l+1+b,0);tot=0;fill(link+1,link+1+c,0);
	for(register int i=1;i<=cnt;i++) if(!flg[p[0][i]]) add(p[1][i],p[2][i]);
	for(register int i=1;i<=b;i++)
	{
		fill(vis+1,vis+1+c,0);
		tmp+=find(i);
	}
	ans=min(ans,tmp);return;
}
int main()
{
	T=read();
	while(T--)
	{
		a=read();b=read();c=read();ans=0x7fffffff;cnt=0;
		minn=min(a,min(b,c));
		for(register int i=1;i<=a;i++)
		 for(register int j=1;j<=b;j++)
		  for(register int k=1;k<=c;k++)
		{
			x=read();
			if(x) p[0][++cnt]=i,p[1][cnt]=j,p[2][cnt]=k;
		}
		if(minn==b) swap(a,b),swap(p[0],p[1]);else if(minn==c) swap(a,c),swap(p[0],p[2]);
		for(register int i=0;i<(1<<a);i++) work(i);
		printf("%d\n",ans);
	}
}

标签:cnt,消毒,times,HNOI2013,int,P3231,edge,read,link
来源: https://blog.csdn.net/xuxiayang/article/details/113838327