首页 > 代码库 > BZOJ 2150 部落战争 最小路径覆盖 二分图最大匹配

BZOJ 2150 部落战争 最小路径覆盖 二分图最大匹配

题目大意:给出一张地图,一个军队要征战整个土地。一块土地只能经过一次,有X的地方不能走,军队只会走R*C个格子,只会向下走,问最少需要多少军队能够征战所有的土地。


思路:这个是前几天考试的题,今天居然发现时BZ的原题,还好当时A掉了。。。

看到每个土地只能经过一次就想到了网络流什么的,再一想想好像是最小路径覆盖啊,然后拆点,建图,Hungary,二分图最小路径覆盖=点数-最大匹配,没了。。


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 20010
using namespace std;

int m,n,r,c;
char src[200][200];
int num[200][200],cnt;

int head[MAX],total;
int _next[MAX],aim[MAX];

bool v[MAX];
int paired[MAX];

inline void Add(int x,int y)
{
	_next[++total] = head[x];
	aim[total] = y;
	head[x] = total;
}

bool Hungary(int x)
{
	for(int i = head[x]; i; i = _next[i]) {
		if(!v[aim[i]]) {
			v[aim[i]] = true;		
			if(!paired[aim[i]] || Hungary(paired[aim[i]])) {
				paired[aim[i]] = x;
				return true;
			}
		}	
	}	
	return false;
}

int main()
{
	cin >> m >> n >> r >> c;
	for(int i = 1; i <= m; ++i) {
		scanf("%s",src[i] + 1);
		for(int j = 1; j <= n; ++j)
			if(src[i][j] == '.')
				num[i][j] = ++cnt;
	}
	for(int i = 1; i <= m; ++i)
		for(int j = 1; j <= n; ++j) {
			if(!num[i][j])	continue;
			if(i + r > 0 && j + c > 0 && num[i + r][j + c])	
				Add(num[i][j],num[i + r][j + c] + cnt);
			if(i + c > 0 && j + r > 0 && num[i + c][j + r])
				Add(num[i][j],num[i + c][j + r] + cnt);
			if(i + r > 0 && j - c > 0 && num[i + r][j - c])
				Add(num[i][j],num[i + r][j - c] + cnt);
			if(i + c > 0 && j - r > 0 && num[i + c][j - r])
				Add(num[i][j],num[i + c][j - r] + cnt);
		}
	int ans = 0;
	for(int i = 1; i <= cnt; ++i) {
		memset(v,false,sizeof(v));
		ans += Hungary(i);
	}
	cout << cnt - ans << endl;
	return 0;
}


BZOJ 2150 部落战争 最小路径覆盖 二分图最大匹配