• bzoj 2150


    然后考虑正解

    我们发现,最坏情况就是每个点都派驻军队,所以答案至多是“.”的数目

    而且,每个点都至多只有一个入度和一个出度,所以我们可以将每个点拆成两个点,一个作为入点,一个作为出点,然后所有图上能到达的点由出点向入点建图

    这样整个图就形成了一个二分图

    然后在整个图上跑二分图匹配即可

    答案即为“.”点数-二分图最大匹配数

    稍微证明一下:我们的目的是最大化有入边的点的数量,那我们仅需让入点能更多的被匹配上即可

    那也就是二分图匹配喽

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
    struct Edge
    {
        int next;
        int to;
    }edge[10005];
    int head[2505];
    int maps[55][55];
    char s[55];
    bool used[6005];
    int f[6005];
    int n,m,r,c;
    int cnt=1,cot;
    queue <int> Q;
    bool check(int x,int y)
    {
        if(x>0&&x<=n&&y>0&&y<=m&&maps[x][y])
        {
            return 1;
        }
        return 0;
    }
    void init()
    {
        memset(head,-1,sizeof(head));
        cnt=1;
    }
    void add(int l,int r)
    {
        edge[cnt].next=head[l];
        edge[cnt].to=r;
        head[l]=cnt++;
    }
    int po(int x,int y)
    {
        return (x-1)*m+y; 
    }
    int ppo(int x,int y)
    {
        return (x-1)*m+y+n*m;
    }
    bool dfs(int x)
    {
        for(int i=head[x];i!=-1;i=edge[i].next)
        {
            int to=edge[i].to;
            if(used[to])
            {
                continue;
            }
            used[to]=1;
            if(!f[to]||dfs(f[to]))
            {
                f[to]=x;
                return 1;
            }
        }
        return 0;
    }
    int hungary()
    {
        int ret=0;
        while(!Q.empty())
        {
            memset(used,0,sizeof(used));
            int u=Q.front();
            Q.pop();
            if(dfs(u))
            {
                ret++;
            }
        }
        return ret;
    }
    int main()
    {
        freopen("legion.in","r",stdin);
        freopen("legion.out","w",stdout);
        scanf("%d%d%d%d",&n,&m,&r,&c);
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s+1);
            for(int j=1;j<=m;j++)
            {
                if(s[j]=='.')
                {
                    maps[i][j]=1;
                    Q.push(po(i,j));
                    cot++;
                }else
                {
                    maps[i][j]=0;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                int x0=i+r;
                int y0=j+c;
                if(check(x0,y0))
                {
                    add(po(i,j),ppo(x0,y0));
                }
                x0=i+r;
                y0=j-c;
                if(check(x0,y0))
                {
                    add(po(i,j),ppo(x0,y0));
                }
                x0=i+c;
                y0=j+r;
                if(check(x0,y0))
                {
                    add(po(i,j),ppo(x0,y0));
                }
                x0=i+c;
                y0=j-r;
                if(check(x0,y0))
                {
                    add(po(i,j),ppo(x0,y0));
                }
            }
        }
        printf("%d
    ",cot-hungary());
        return 0;
    }
  • 相关阅读:
    PHP javascript cookie
    angular.js初探
    熟悉陌生框架或代码, 产品设计小结
    question2answer论坛框架分析及web开发思考
    一个很好用的系统管理的命令lsof(转载)
    Linux nc命令用法收集
    Linux IO实时监控iostat命令详解(转载)
    AIX中查找端口号和进程
    bash之局部变量与子shell(转载)
    Linux下产生随机密码10方法
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9756492.html
Copyright © 2020-2023  润新知