zoukankan      html  css  js  c++  java
  • [ZJOI2009]狼和羊的故事

    https://www.luogu.org/problem/show?pid=2598

    题目描述

    “狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。

    输入输出格式

    输入格式:

    文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。

    输出格式:

    文件中仅包含一个整数ans,代表篱笆的最短长度。

    输入输出样例

    输入样例#1:
    2 2
    2 2 
    1 1 
    输出样例#1:
    2
    

    说明

    数据范围

    10%的数据 n,m≤3

    30%的数据 n,m≤20

    100%的数据 n,m≤100

    源点向羊连流量为inf的边,狼向汇点连流量为inf的边

    羊向相邻的狼连流量为1的边

    羊向相邻的空地连流量为1的边

    狼向相邻的空地连流量为1的边

    空地之间连流量为1的边

    相邻指上下左右,均是单向边

    空地之间需要双向边,但两块两邻空地会枚举两边,所以相当于连了双向边

    最小割就是答案

    #include<queue>
    #include<cstdio>
    #define N 101
    
    using namespace std;
    
    const int inf=2e9;
    
    int n,m,a[N][N];
    int src,decc,ans;
    int dx[4]={-1,0,1,0};
    int dy[4]={0,1,0,-1};
    int front[N*N],to[N*N*10],nxt[N*N*10],cap[N*N*10],tot=1;
    int cnt[N*N],lev[N*N];
    
    queue<int>q;
    
    void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; cap[tot]=w;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; cap[tot]=0;
    }
    int turn(int i,int j)
    {
        return (i-1)*m+j;
    }
    bool bfs()
    {
        for(int i=src;i<=decc;i++) lev[i]=-1,cnt[i]=front[i];
        while(!q.empty()) q.pop();
        q.push(src); lev[src]=0;
        int now;
        while(!q.empty())
        {
            now=q.front(); q.pop();
            for(int i=cnt[now];i;i=nxt[i])
                if(lev[to[i]]==-1 && cap[i])
                {
                    lev[to[i]]=lev[now]+1;
                    q.push(to[i]);
                    if(to[i]==decc) return true; 
                }
        }
        return false;
    }
    int dinic(int now,int flow)
    {
        if(now==decc) return flow;
        int delta,rest=0;
        for(int &i=cnt[now];i;i=nxt[i])
        {
            if(cap[i] && lev[to[i]]>lev[now])
            {
                delta=dinic(to[i],min(flow-rest,cap[i]));
                if(delta) 
                {
                    rest+=delta;
                    cap[i]-=delta; cap[i^1]+=delta;
                    if(rest==flow) break;
                }
            }
        }
        if(rest!=flow) lev[now]=-1;
        return rest;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        decc=n*m+1;
        for(int i=1;i<=n;i++)
         for(int j=1;j<=m;j++)
          {
               scanf("%d",&a[i][j]);
               if(a[i][j]==2) add(src,turn(i,j),inf);
             else if(a[i][j]==1) add(turn(i,j),decc,inf);  
          }
        for(int i=1;i<=n;i++)
         for(int j=1;j<=m;j++)
         {
            if(a[i][j]==1)
             {
                 for(int k=0;k<4;k++)
                 if(i+dx[k]>0 && i+dx[k]<=n && j+dy[k]>0 && j+dy[k]<=m && !a[i+dx[k]][j+dy[k]]) 
                   add(turn(i+dx[k],j+dy[k]),turn(i,j),1);
             }
            else if(a[i][j]==2)
             {
                 for(int k=0;k<4;k++)
                 if(i+dx[k]>0 && i+dx[k]<=n && j+dy[k]>0 && j+dy[k]<=m &&a[i+dx[k]][j+dy[k]]!=a[i][j]) 
                  add(turn(i,j),turn(i+dx[k],j+dy[k]),1);
             }
            else
             for(int k=0;k<4;k++)
              if(i+dx[k]>0 && i+dx[k]<=n && j+dy[k]>0 && j+dy[k]<=m && !a[i+dx[k]][j+dy[k]]) 
                add(turn(i,j),turn(i+dx[k],j+dy[k]),1);
         }
        while(bfs()) ans+=dinic(src,inf);
        printf("%d",ans);
    }
  • 相关阅读:
    Code Reading chap2
    Code Reading chap4
    Code Reading chap6
    常用的一些sql基础语句汇总
    20170322、Linux常用命令汇总
    在windows上部署使用Redis
    20170322、php基础语法
    20170822、在Linux上部署使用Redis
    Linux安装配置SVN服务器
    Linux安装配置MySQL
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7039536.html
Copyright © 2011-2022 走看看