jzoj6299. 工厂

Description
在这里插入图片描述

Input
在这里插入图片描述

Output
在这里插入图片描述

Sample Input
Sample 1:
2
11
10

Sample 2:
2
10
00

Sample 3:
3
000
110
000

Sample Output
Sample 1:
1

Sample 2:
1

Sample 3:
3

Data Constraint
在这里插入图片描述

Hint
在这里插入图片描述

扫描二维码关注公众号,回复: 12794608 查看本文章

题解

论想到正解却没打出来是怎样一种体验
若两个人之间有边,则代表这两个人有同一种能操作的机器
把人划分成几个集合,每个集合都是一个极大连通图,设集合中有w个人,有h种机器(可以通过移动行/列把集合变成矩形)
对于每个w=h的集合,若该集合未满,则必定有一种不合法的情况
证明:
假设工人a选了他不能选的机器,考虑寻找一种剩余的匹配方案
①没有合法匹配
若选了不合法的情况后剩下的都不能合法,那么结果必然不合法
②有合法匹配
则剩余的人可以选这样一个匹配,那么a只能选自己不能选的,也必然不合法

若一个集合w≠h,那么就算可以匹配,也必然出现剩人/剩机器的情况
所以要把若干w≠h的集合组合成∑w=∑h的大集合
状压,把行和列都相同的压在一起,最后状态数不会很多

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;

int p[31];
int A[31];
struct type{
    
    
	int w,h,s;
} a[61],b[61];
int c[61];
int bz[31];
int f[172033];
int n,I,i,j,k,l,s,w,h,tot,ans,L;
char ch;
bool Bz;

int Get()
{
    
    
	ch=getchar();
	while (ch<'0' || ch>'1')
	ch=getchar();
	
	return (ch=='1');
}

bool cmp(type a,type b)
{
    
    
	return a.w<b.w || a.w==b.w && a.h<b.h;
}

void dfs(int t,int s,int w,int h)
{
    
    
	int i;
	
	if (t>tot)
	{
    
    
		if (w==h)
		f[I]=min(f[I],f[I-s]+w*h);
		
		return;
	}
	
	fo(i,0,c[t])
	dfs(t+1,s*(b[t].s+1)+i,w+i*b[t].w,h+i*b[t].h);
}

int main()
{
    
    
	freopen("factory.in","r",stdin);
	freopen("factory.out","w",stdout);
	
	scanf("%d",&n);
	p[1]=1;
	fo(i,2,n)
	p[i]=p[i-1]<<1;
	
	fo(i,1,n)
	{
    
    
		fo(j,1,n)
		{
    
    
			k=Get();
			A[i]=A[i]*2+k;
		}
	}
	
	fo(l,1,n)
	if (!bz[l])
	{
    
    
		bz[l]=l;
		s=A[l];
		
		w=0;
		h=1;
		
		Bz=1;
		while (Bz)
		{
    
    
			Bz=0;
			
			fo(i,1,n)
			if (!bz[i] && (s&A[i]))
			{
    
    
				bz[i]=l;
				s|=A[i];
				++h;
				
				Bz=1;
			}
		}
		
		j=s;
		while (j)
		{
    
    
			w+=j&1;
			j>>=1;
		}
		
		if (!w)
		h=0;
		
		if (w!=h)
		{
    
    
			++tot;
			a[tot].w=w;
			a[tot].h=h;
		}
		else
		ans+=w*h;
		
		fo(i,1,n)
		if (bz[i]==l)
		{
    
    
			j=A[i]&s;
			k=0;
			
			while (j)
			{
    
    
				k+=j&1;
				j>>=1;
			}
			
			ans-=k;
		}
	}
	
	j=0;
	k=0;
	fo(i,1,n)
	if (!A[i])
	{
    
    
		++tot;
		a[tot].w=0;
		a[tot].h=1;
	}
	fo(i,1,n)
	{
    
    
		fo(j,1,n)
		if (A[j]&p[i])
		break;
		
		if (j>n)
		{
    
    
			++tot;
			a[tot].w=1;
			a[tot].h=0;
		}
	}
	
	sort(a+1,a+tot+1,cmp);
	
	j=0;
	fo(i,1,tot)
	{
    
    
		if (i==1 || a[i].w!=a[i-1].w || a[i].h!=a[i-1].h)
		{
    
    
			++j;
			b[j].w=a[i].w;
			b[j].h=a[i].h;
			b[j].s=1;
		}
		else
		++b[j].s;
	}
	tot=j;
	
	L=1;
	fo(i,1,tot)
	L*=b[i].s+1;
	--L;
	
	memset(f,1,sizeof(f));
	f[0]=0;
	fo(I,1,L)
	{
    
    
		k=I;
		fd(j,tot,1)
		{
    
    
			c[j]=k%(b[j].s+1);
			k/=b[j].s+1;
		}
		
		dfs(1,0,0,0);
	}
	
	printf("%d\n",ans+f[L]);
}

猜你喜欢

转载自blog.csdn.net/gmh77/article/details/99400329