洛谷P2172 [bzoj] 2150 部落战争

P2172 [国家集训队]部落战争

题目描述

lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土。

A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住。lanzerb把自己的部落分成若干支军队,他们约定:

  1. 每支军队可以从任意一个城镇出发,并只能从上往向下征战,不能回头。途中只能经过城镇,不能经过高山深涧。

  2. 如果某个城镇被某支军队到过,则其他军队不能再去那个城镇了。

  3. 每支军队都可以在任意一个城镇停止征战。

  4. 所有军队都很奇怪,他们走的方法有点像国际象棋中的马。不过马每次只能走1*2的路线,而他们只能走R*C的路线。

lanzerb的野心使得他的目标是统一全国,但是兵力的限制使得他们在配备人手时力不从心。假设他们每支军队都能顺利占领这支军队经过的所有城镇,请你帮lanzerb算算至少要多少支军队才能完成统一全国的大业。

输入输出格式

 

输入格式:

第一行包含4个整数M、N、R、C,意义见问题描述。接下来M行每行一个长度为N的字符串。如果某个字符是'.',表示这个地方是城镇;如果这个字符时'x',表示这个地方是高山深涧。

 

输出格式:

输出一个整数,表示最少的军队个数。

 

输入输出样例

输入样例#1: 复制
3 3 1 2
...
.x.
...
输出样例#1: 复制
4
输入样例#2: 复制
5 4 1 1
....
..x.
...x
....
x...
输出样例#2: 复制
5

说明

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( );
}
posted @ 2018-10-16 11:55  阿澈说他也想好好学习  阅读(188)  评论(0编辑  收藏  举报