zoukankan      html  css  js  c++  java
  • 洛谷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
    ",cnt - ans);
    }
    
    int main( ) {
        
        Init( );
        Solve( );
    }
  • 相关阅读:
    从原生web组件到框架组件源码(二)
    从原生web组件到框架组件源码(一)
    拖拽滚动视图(一)
    SVG研究之路(一)下
    运算符
    编码
    格式化输出
    循环语句
    条件语句
    Python基础
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9797161.html
Copyright © 2011-2022 走看看