UESTC-1963咸鱼咕咕咕(二分图匹配)
咸鱼咕咕咕
Time Limit: 1000 MS Memory Limit: 64 MB
咸鱼
有个咕咕笼。
咕咕笼可以划分成m×nm×n个格子,每个小格子可以放下一只咕咕
,也可以放下一个咕咕槽。
现在咕咕笼里有若干只咕咕
。
放在咕咕笼里的咕咕
能够看到他上下左右四个方向上的所有格子。
当然,因为咕咕槽比较高,那群咕咕
没办法看见咕咕槽后面的咕咕
。
咸鱼
发现如果两只咕咕
能够看见对方,他们会在咸鱼离开的时候跑在一起形成更大的咕咕咕咕
,否则他们只会像条咸鱼一样安心待在那里咕咕。
现在咸鱼
不希望他们形成咕咕咕咕
,需要带走一些咕咕
。
但是带走太多的咕咕
会让咸鱼
咕咕咕咕。
咸鱼
希望你能帮他决定至少应该带走多少只咕咕
。
Input
第一行两个整数mm,nn。(1≤m,n≤50)(1≤m,n≤50)
接下来mm行,每行一个字符串,含有nn个字符。
第ii个字符串第jj个字符表示了咕咕笼第ii行第jj列的情况。
若字符为o
,表示这上面有只咕咕
。
若字符为+
,表示这上面有个咕咕槽。
若字符为.
,表示上面既没有咕咕
,也没有咕咕槽。
Output
输出咸鱼
至少应该带走多少只咕咕
。
Sample input and output
Sample Input | Sample Output |
---|---|
2 2 o+ .o | 0 |
2 5 o+.o+ .o..o | 1 |
1 1 . | 0 |
Hint
Sample 1: 不需要带走咕咕
。
Sample 2: 至少需要带走(2,2)(2,2)或(2,5)(2,5)其中一只咕咕
,不然他们会在咸鱼
离开后变成咕咕咕咕
。
Sample 3: 没有咕咕
可带。
题解:
这一题最主要的就是建图,我们可以这么考虑,如果同一行中的两个咕咕之间存在咕咕槽,则把他们当做不同行去处理,如果同一列中的两个咕咕之间存在咕咕槽,则把他们当做不同列去处理。然后行作为一个集合,列作为一个集合,做二分图匹配,最终答案则是咕咕数减去最大匹配数。
为什么可以这么做呢?因为如果某一行中没有咕咕槽的话,那么这一行只允许存在一个咕咕(因为如果存在两个或两个以上的咕咕会形成咕咕咕咕),对于列也是如此。如果有咕咕槽,咕咕槽两边的咕咕可以同时存在于同一行或同一列,为了转化为二分图匹配的问题,我们就可以把他们当成不同行或不同列。二分图最大匹配就可以求出最终矩阵中最多可以放置多少个咕咕且不会形成咕咕咕咕。
AC代码为:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5;
char s[1000][1000];
int n,m,o,p,sum,num,i,j,k,kk,q,ii,e[maxn],f[maxn],c[maxn],d[maxn],a[maxn],b[maxn],link[2555][2555],girl[10000],used[10000];
bool found(int x)
{
for (int i=1;i<=kk;i++)
if (link[x][i]&&!used[i])
{
used[i]=1;
if (girl[i]==0||found(girl[i]))
{
girl[i]=x;
return(1);
}
}
return(0);
}
int main()
{
cin>>m>>n;
for (i=1;i<=m;i++)
cin>>s[i];
o=0;
for (i=1;i<=m;i++)
{
for (j=0;j<=n-1;j++)
if (s[i][j]=='o')
{
p=0; q=0;
for (ii=0;ii<j;ii++)
if (s[i][ii]=='+') p++;
for (ii=1;ii<i;ii++)
if (s[ii][j]=='+') q++;
o+=1;
a[o]=i+p*m;
b[o]=j+1+q*n;
}
}
for (i=1;i<=o;i++)
{
e[i]=a[i];
f[i]=b[i];
}
sort(a+1,a+1+o);
sort(b+1,b+1+o);
c[a[1]]=1;
k=1;
for (i=2;i<=o;i++)
if (a[i]==a[i-1]) c[a[i]]=k; else {k++;c[a[i]]=k;}
d[b[1]]=1;
kk=1;
for (i=2;i<=o;i++)
if (b[i]==b[i-1]) d[b[i]]=kk; else {kk++;d[b[i]]=kk;}
for (i=1;i<=o;i++)
link[c[e[i]]][d[f[i]]]=1;
for (i=1;i<=kk;i++)
girl[i]=0;
num=0;
for (i=1;i<=k;i++)
{
memset(used,0,sizeof(used));
if (found(i)) num++;
}
printf("%d\n",o-num);
return(0);
}