部落战争
Problem Description
lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土。
A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住。lanzerb把自己的部落分成若干支军队,他们约定:
每支军队可以从任意一个城镇出发,并只能从上往向下征战,不能回头。途中只能经过城镇,不能经过高山深涧。
如果某个城镇被某支军队到过,则其他军队不能再去那个城镇了。
每支军队都可以在任意一个城镇停止征战。
所有军队都很奇怪,他们走的方法有点像国际象棋中的马。不过马每次只能走12的路线,而他们只能走RC的路线。
lanzerb的野心使得他的目标是统一全国,但是兵力的限制使得他们在配备人手时力不从心。假设他们每支军队都能顺利占领这支军队经过的所有城镇,请你帮lanzerb算算至少要多少支军队才能完成统一全国的大业。
Input
第一行包含4个整数M、N、R、C,意义见问题描述。接下来M行每行一个长度为N的字符串。如果某个字符是’.’,表示这个地方是城镇;如果这个字符时’x’,表示这个地方是高山深涧。
Output
输出一个整数,表示最少的军队个数。
Sample Input
输入样例1:
3 3 1 2
…
.x.
…
输入样例2:
5 4 1 1
…
…x.
…x
…
x…
输入样例3:
1 1 1 1
.
Sample Output
输出样例1:
4
输出样例2:
5
输出样例3:
1
题解:
将每个点重新编号,若
(
i
,
j
)
(i,j)
(i,j)能转移到点
(
x
,
y
)
(x,y)
(x,y),则连边。
所有点编号并连边后,可得到一个DAG图。
初始点任意,求每个点最多允许一次停留=>DAG不相交的最小路径覆盖。
将DAG图中的,每个点拆分为两个点,对于边
i
−
>
j
i->j
i−>j,连边
i
i
−
>
j
2
i_i->j_2
ii−>j2。
新图为二分图,求其最大匹配。点的总数-最大匹配 即为所求。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 5020;
const int mod = 1000000007;
int id[52][52], dx[4], dy[4], vis[maxn], visy[maxn], mat[maxn];
char str[52][52];
vector<int> g[maxn];
bool Find(int u);
int match(int n, int m);
int main()
{
int n, m, i, j, k, cnt=0, r, c;
scanf("%d %d %d %d", &n, &m, &r, &c);
dx[0] = dx[1] = r, dx[2] = dx[3] = c;
dy[0] = c, dy[1] = -c, dy[2] = r, dy[3] = -r;
for(i=0;i<n;i++)
scanf(" %s", str[i]);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(str[i][j] == '.')id[i][j] = ++cnt;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(str[i][j] == '.')
for(k=0;k<4;k++){
int nx = i+dx[k], ny = j+dy[k];
if(nx>=0 && nx<n && ny>=0 && ny<m && str[nx][ny] == '.')
g[id[i][j]].push_back(id[nx][ny]);
}
int ans;
ans = match(cnt, cnt);
printf("%d\n", cnt-ans);
return 0;
}
int match(int n, int m)
{
int ans = 0;
memset(mat, 0, sizeof(mat));
for(int i=1;i<=m;i++){
memset(vis, 0, sizeof(vis));
if(Find(i))ans++;
}
return ans;
}
bool Find(int u)
{
for(int i=0;i<g[u].size();i++){
int v = g[u][i];
if(vis[v])continue;
vis[v] = 1;
if(!mat[v] || Find(mat[v])){
mat[v] = u;
return true;
}
}
return false;
}