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
题解
论想到正解却没打出来是怎样一种体验
若两个人之间有边,则代表这两个人有同一种能操作的机器
把人划分成几个集合,每个集合都是一个极大连通图,设集合中有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]);
}