题目链接:3041 Asteroids
先说行星这题,题意说可以一次操作消去一行或一列的行星,问全部消去所需要的最小操作次数。
给出例图:
# |
|
# |
# |
||
# |
|
按行消:
1 | 1 | |
2 | ||
3 |
按列消:
1 | 3 | |
2 | ||
2 |
由此我们构造出一个按点消去的map2;
对于第一点:1-1;第三点:1-3;第五点:2-2;第八点:3-2。接下来用匈牙利算法找出map2的最大匹配数。
对于我们得出的这四条线,均是按点连接行和列的关系,如第一点,可以通过消去第一行或第一列消去第一点。
等等,我们明明要找最小消去步数,怎么突然变成了找最大匹配数?
原因很简单,因为我们首先要确定全部消去,故而找的是行和列的最大匹配数(才能保证全部消去),而在查找最大匹配数时,我们总是尽量让所有行匹配上列(匈牙利算法的要求),所以只要全部匹配成功,那么自然求出的就是最小步数了。
再看田野这一题,题目是按行或列消,但是遇到" . "就不能继续消了。
对于例子:
# | # | ||
# | # | # | |
# | # | # | |
# |
按行:
1 | 1 | ||
2 | 2 | 2 | |
3 | 3 | 3 | |
4 |
按列:
1 | 4 | ||
3 | 4 | 5 | |
2 | 3 | 4 | |
4 |
构建map2:
1-1、1-4、2-3、2-4、2-5、3-2、3-3、3-4、4-4。
不多话,附上代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
bool map[55][55];
bool map2[2567][2567];
int R[55][55];
int C[55][55];
bool vis[2567];
int linker[2567];
int Rn,Ln;
bool find(int x)
{
for(int i=1;i<=Ln;i++)
{
if(map2[x][i]&&!vis[x])
{
vis[x]=1;
if(!linker[i]||find(linker[i]))
{
linker[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int r,l;
char c;
while(cin>>r>>l)
{
for(int i=1;i<=r;i++)
{
for(int j=1;j<=l;j++)
{
cin>>c;
if(c=='*') map[i][j]=1;
else map[i][j]=0;
}
getchar();
}
int a=0,b=0;
for(int i=1;i<=r;i++)
{
for(int j=1;j<=l;j++)
{
if(map[i][j]==1)a++;
while(map[i][j]==1) R[i][j++]=a;
}
}
for(int i=1;i<=l;i++)
{
for(int j=1;j<=r;j++)
{
if(map[j][i]==1) b++;
while(map[j][i]==1) C[j++][i]=b;
}
}
for(int i=1;i<=r;i++)
{
for(int j=1;j<=l;j++)
{
if(map[i][j]) map2[R[i][j]][C[i][j]]=1;
}
}
Rn=a;
Ln=b;
int ans=0;
memset(linker,0,sizeof(linker));
for(int i=1;i<=a;i++)
{
memset(vis,0,sizeof(vis));
if(find(i)) ans++;
}
cout<<ans<<endl;
}
return 0;
}