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

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 4017  Solved: 2037
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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

    Sample Input

    2 2
    2 2
    1 1

    Sample Output

    2

    数据范围
    10%的数据 n,m≤3
    30%的数据 n,m≤20
    100%的数据 n,m≤100
     
    开始以为是最大染色之类的问题,查题解发现居然是最大流最小割
    栅栏问题可以转换为,存在两个集合,之间不存在通路,正好符合最小割的定义
    开始建图
    从源点S连向狼,容量为INF
    从羊连向汇点T,容量为INF
    从狼连向相邻的羊和空地,容量为1
    从空地连向相邻的羊和空地,容量为1
     
    跑一边最大流,代码意外的简洁
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<queue>
     5 using namespace std;
     6 
     7 #define get(i,j) ((i-1)*m+j)
     8 const int INF=0x7f7f7f7f;
     9 const int MAXN=400000;
    10 const int xx[4]={-1,1,0,0},yy[4]={0,0,-1,1};
    11 
    12 struct Edge
    13 {
    14     int to,w,next;
    15 }E[MAXN];
    16 int node=1,head[MAXN],dis[MAXN],mp[200][200];
    17 int s=0,t=10001;
    18 int n,m,ans;
    19 
    20 void insert(int u,int v,int w)
    21 {
    22     E[++node]=(Edge){v,w,head[u]};
    23     head[u]=node;
    24     E[++node]=(Edge){u,0,head[v]};
    25     head[v]=node;
    26 }
    27 
    28 bool bfs()
    29 {
    30     memset(dis,-1,sizeof(dis));
    31     queue<int> Q;
    32     Q.push(s);
    33     dis[s]=0;
    34     while(!Q.empty())
    35     {
    36         int q=Q.front();Q.pop();
    37         for(int i=head[q];i;i=E[i].next)
    38             if(E[i].w&&dis[E[i].to]==-1)
    39             {
    40                 Q.push(E[i].to);
    41                 dis[E[i].to]=dis[q]+1;
    42             }
    43     }
    44     return dis[t]!=-1;
    45 }
    46 
    47 int dfs(int x,int flow)
    48 {
    49     if(x==t) return flow;
    50     int w,used=0;
    51     for(int i=head[x];i;i=E[i].next)
    52         if(E[i].w&&dis[E[i].to]==dis[x]+1)
    53         {
    54             w=flow-used;
    55             w=dfs(E[i].to,min(w,E[i].w));
    56             E[i].w-=w;
    57             E[i^1].w+=w;
    58             used+=w;
    59             if(used==flow)return flow;
    60         }
    61     if(!used) dis[x]=-1;
    62     return used;
    63 }
    64 
    65 void dinic()
    66 {
    67     while(bfs()) ans+=dfs(s,INF);
    68 }
    69 
    70 int main()
    71 {
    72     scanf("%d%d",&n,&m);
    73     for(int i=1;i<=n;i++)
    74         for(int j=1;j<=m;j++)
    75         {
    76             scanf("%d",&mp[i][j]);
    77             if(mp[i][j]==1) insert(s,get(i,j),INF);
    78             else if(mp[i][j]==2) insert(get(i,j),t,INF);
    79         }
    80     for(int i=1;i<=n;i++)
    81         for(int j=1;j<=m;j++)
    82             for(int k=0;k<4;k++)
    83             {
    84                 int x=i+xx[k],y=j+yy[k];
    85                 if(x<1||x>n||y<1||y>m) continue;
    86                 if(mp[i][j]!=1||mp[x][y]!=1)
    87                     insert(get(i,j),get(x,y),1);
    88             }
    89     dinic();
    90     printf("%d",ans);
    91     return 0;
    92 }
  • 相关阅读:
    面向对象编程的三大特征: 封装、继承、多态
    CDH和HDP对比
    mapreduce、spark、tez区别
    minio原理和使用
    HDP、CDH、CDP升级
    常用的分布式文件系统
    linux平台下防火墙iptables原理(转)
    php 1207
    php 1209
    php 1130
  • 原文地址:https://www.cnblogs.com/InWILL/p/9735856.html
Copyright © 2011-2022 走看看