洛谷P2172 [bzoj] 2150 部落战争
题目描述
lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土。
A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住。lanzerb把自己的部落分成若干支军队,他们约定:
-
每支军队可以从任意一个城镇出发,并只能从上往向下征战,不能回头。途中只能经过城镇,不能经过高山深涧。
-
如果某个城镇被某支军队到过,则其他军队不能再去那个城镇了。
-
每支军队都可以在任意一个城镇停止征战。
-
所有军队都很奇怪,他们走的方法有点像国际象棋中的马。不过马每次只能走1*2的路线,而他们只能走R*C的路线。
lanzerb的野心使得他的目标是统一全国,但是兵力的限制使得他们在配备人手时力不从心。假设他们每支军队都能顺利占领这支军队经过的所有城镇,请你帮lanzerb算算至少要多少支军队才能完成统一全国的大业。
输入输出格式
输入格式:
第一行包含4个整数M、N、R、C,意义见问题描述。接下来M行每行一个长度为N的字符串。如果某个字符是'.',表示这个地方是城镇;如果这个字符时'x',表示这个地方是高山深涧。
输出格式:
输出一个整数,表示最少的军队个数。
输入输出样例
说明
100%的数据中,1<=M,N<=50,1<=R,C<=10。
这道题其实还是比较简单的 这么小的数据范围一看就是一个而粪土二分图匹配
对于每一个合法点点 就将他向能够到达的点点连边 (先拆点) 跑一边二分图最大匹配即可
答案就是总的点点数量再减去匹配数 因为每匹配一次 代表这个城镇可以被军队直接一网打尽 也就是少使用一支军队
代码
#include <bits/stdc++.h> using namespace std; const int N = 1e4 + 5; bool vis[N]; int zl[5][2], cy[N], cx[N], head[N], nex[2 * N], tov[2 * N]; int tot, cnt, n, m, r, c; char a[100][100]; void add(int u, int v) { tot ++; nex[tot] = head[u]; tov[tot] = v; head[u] = tot; } void Init( ) { scanf("%d%d%d%d",& n,& m,& r,& c); zl[1][0] = c, zl[1][1] = r; zl[2][0] = c, zl[2][1] = -r; zl[3][0] = r, zl[3][1] = c; zl[4][0] = r, zl[4][1] = -c; for(int i = 1;i <= n;i ++) scanf("%s",a[i] + 1); for(int i = 1;i <= n;i ++) { for(int j = 1;j <= m;j ++) { if(a[i][j] == '.') { cnt ++; for(int k = 1;k <= 4;k ++) { int xx = i + zl[k][0], yy = j + zl[k][1]; int v = (xx - 1) * m + yy; if(xx < 1 || xx > n || yy < 1 || yy > m || a[xx][yy] != '.') continue; add((i - 1) * m + j, v + n * m); } } } } } int dfs(int x) { for(int i = head[x];i;i = nex[i]) { int v = tov[i]; if(! vis[v]) { vis[v] = true; if(! cx[v] || dfs(cx[v])) { cx[v] = x; cy[x] = v; return 1; } } } return 0; } void Solve( ) { int ans = 0; for(int i = 1;i <= n * m;i ++) { if(! cy[i]) { memset(vis, 0, sizeof(vis)); ans += dfs(i); } } printf("%d\n",cnt - ans); } int main( ) { Init( ); Solve( ); }