zoukankan      html  css  js  c++  java
  • 【洛谷】4304:[TJOI2013]攻击装置【最大点独立集】【二分图】2172: [国家集训队]部落战争【二分图/网络流】【最小路径覆盖】

    P4304 [TJOI2013]攻击装置

    题目描述

    给定一个01矩阵,其中你可以在0的位置放置攻击装置。 每一个攻击装置(x,y)都可以按照“日”字攻击其周围的8个位置(x-1,y-2),(x-2,y-1),(x+1,y-2),(x+2,y-1),(x-1,y+2),(x-2,y+1),(x+1,y+2),(x+2,y+1)

    求在装置互不攻击的情况下,最多可以放置多少个装置。

    输入输出格式

    输入格式:

     

    第一行一个整数N,表示矩阵大小为N*N。

    接下来N行每一行一个长度N的01串,表示矩阵。

     

    输出格式:

     

    一个整数,表示在装置互不攻击的情况下最多可以放置多少个装置。

    输入输出样例

    输入样例#1: 复制
    3
    010
    000
    100
    输出样例#1: 复制
    4

    说明

    30%数据N<=50

    100%数据 N<=200


    Solution

    求最大点独立集,最大点独立集=点集-最大匹配

    这道题因为是会相互连边,所以最后最大匹配数除以2就行了。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    
    struct Node {
        int u, v, nex;
        Node(int u = 0, int v = 0, int nex = 0) :
            u(u), v(v), nex(nex) { }
    } Edge[4000005];
    
    int h[100005], stot;
    void add(int u, int v) {
        Edge[++stot] = Node(u, v, h[u]);
        h[u] = stot;
    }
    
    int n;
    char s[205][205];
    
    int zl[9][2] = {{-1, -2}, {-2, -1}, {2, 1}, {1, 2}, {1, -2}, {-2, 1}, {-1, 2}, {2, -1}};
    int vis[100005], las[100005], to[100005], G[100005], id[205][205], t;
    
    bool dfs(int u) {
        for(int i = h[u]; i; i = Edge[i].nex) {
            int v = Edge[i].v;
            if(vis[v] != t) {
                vis[v] = t;
                if(!las[v] || dfs(las[v])) {
                    las[v] = u; to[u] = v;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    bool pd(int x, int y) {
        if(x < 0 || y < 0 || x > n || y > n || !G[id[x][y]])    return 0;
        return 1;
    }
    
    int main() {
        int tot = 0, ans = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++)    scanf("%s", s[i] + 1);
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= n; j ++) {
                id[i][j] = (i - 1) * n + j;
                if(s[i][j] == '0')    G[id[i][j]] = 1, tot ++;
                else                G[id[i][j]] = 0;
            }
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= n; j ++) {
                if(!G[id[i][j]])    continue;
                for(int k = 0; k < 8; k ++) {
                    int x = i + zl[k][0], y = j + zl[k][1];
                    if(!pd(x, y))    continue;
                    add(id[i][j], id[x][y] + n * n);
                }
            }
        for(int i = 1; i <= n * n; i ++)
            if(!to[i] && G[i]) {
                t ++;
                ans += dfs(i);
            }
        printf("%d", tot - ans / 2);
        return 0;
    }

    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。


    Solution

    比较轻松地可以想到最小路径覆盖问题,用最少的路径,经过所有点。

    二分图是经典方法,每个点拆点,两点间有连边就在二分图上连边,最小路径=总点数-最大匹配。可以理解为,每一个匹配,就省去了一条路径(以入点为起点的路径可以由出点直接到达),所以最大匹配省去的路径是最多的。

    最大匹配也可以用网络流实现。

    注意空间....

    Code

    #include<bits/stdc++.h>
    using namespace std;
    
    int G[105][105], n, m, r, c;
    int zl[2][2] = {{1, 1}, {1, -1}};
    
    struct Node {
        int u, v, nex;
        Node(int u = 0, int v = 0, int nex = 0) :
            u(u), v(v), nex(nex) { }
    } Edge[1000005];
    
    int h[10005], stot;
    void add(int u, int v) {
        Edge[++stot] = Node(u, v, h[u]);
        h[u] = stot;
    }
    
    bool check(int x, int y) {
        if(x < 1 || y < 1 || x > m || y > n || !G[x][y])    return 0;
        return 1;
    }
    
    int las[10005], to[10005], vis[10005];
    bool dfs(int u) {
        for(int i = h[u]; i; i = Edge[i].nex) {
            int v = Edge[i].v;
            if(!vis[v]) {
                vis[v] = 1;
                if(!las[v] || dfs(las[v])) {
                    to[u] = v; las[v] = u;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int id[105][105], ans, tot;
    char s[505][505];
    int main() {
        scanf("%d%d%d%d
    ", &m, &n, &r, &c);
        for(int i = 1; i <= m; i ++)    scanf("%s", s[i] + 1);
        for(int i = 1; i <= m; i ++) {
            for(int j = 1; j <= n; j ++) {
                id[i][j] = (i - 1) * n + j;
                if(s[i][j] == '.')    G[i][j] = 1, tot ++;
                else            G[i][j] = 0;
            }
        }
        for(int i = 1; i <= m; i ++)
            for(int j = 1; j <= n; j ++) {
                if(!G[i][j])    continue;
                int x, y;
                for(int k = 0; k < 2; k ++) {
                    x = i + zl[k][0] * r, y = j + zl[k][1] * c;
                    if(!check(x, y))    continue;
                    add(id[i][j], id[x][y] + n * m);
                }
                if(r != c) {
                    for(int k = 0; k < 2; k ++) {
                        x = i + zl[k][0] * c, y = j + zl[k][1] * r;
                        if(!check(x, y))    continue;
                        add(id[i][j], id[x][y] + n * m);
                    }
                }
            }
        for(int i = 1; i <= m; i ++) {
            for(int j = 1; j <= n; j ++)
                if(!to[id[i][j]] && G[i][j]) {
                    memset(vis, 0, sizeof(vis));
                    ans += dfs(id[i][j]);
                }
        }
        printf("%d", tot - ans);
        return 0;
    }
  • 相关阅读:
    preg_replace函数/e后门
    php7.0-7.3的bypass disable_function一把梭
    PHP反序列化逃逸
    day2filter_var函数漏洞
    基于 Elasticsearch 聚合搜索实现电商筛选查询功能
    基于SpringBoot + Redis + 轮询实现扫码登录
    教你理解Lambda表达式
    记录解决 Elasticseach 过滤与聚合问题
    基于 MyBatis-Plus 解决数据库逻辑删除与唯一索引问题
    Java8 Stream Lamdba sorted()排序遇到的小坑
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9798727.html
Copyright © 2011-2022 走看看