• [ZJOI2009]狼和羊的故事


    题目描述

    “狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” 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

    最小割题目

    羊连S点,狼连T点

    相邻点连流量为1的边

    原题就变成了断开S和T的最小代价,这就是最小割

    对于空点,应当介于羊和狼之间

    注意连边的细节

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<queue>
      7 using namespace std;
      8 struct Node
      9 {
     10   int next,to,cap;
     11 }edge[200001];
     12 int head[20001],num=1,dist[20001],cur[20001],n,m,id[101][101],a[101][101],cnt,ans;
     13 int inf=2e9;
     14 void add(int u,int v,int cap)
     15 {
     16   num++;
     17   edge[num].next=head[u];
     18   head[u]=num;
     19   edge[num].to=v;
     20   edge[num].cap=cap;
     21   num++;
     22   edge[num].next=head[v];
     23   head[v]=num;
     24   edge[num].to=u;
     25   edge[num].cap=0;
     26 }
     27 bool bfs(int S,int T)
     28 {int i;
     29   queue<int>Q;
     30   memset(dist,-1,sizeof(dist));
     31   Q.push(S);
     32   dist[S]=0;
     33   while (Q.empty()==0)
     34     {
     35       int u=Q.front();
     36       Q.pop();
     37       for (i=head[u];i!=-1;i=edge[i].next)
     38     {
     39       int v=edge[i].to;
     40       if (dist[v]==-1&&edge[i].cap)
     41         {
     42           dist[v]=dist[u]+1;
     43           Q.push(v);
     44         }
     45     }
     46     }
     47   if (dist[T]==-1) return 0;
     48   return 1;
     49 }
     50 int dfs(int x,int des,int flow)
     51 {
     52   int res=0,tmp;
     53   if (flow<=0||x==des) return flow;
     54   for (int &i=cur[x];i!=-1;i=edge[i].next)
     55     {
     56       int v=edge[i].to;
     57       if (dist[v]!=dist[x]+1||edge[i].cap==0) continue;
     58       tmp=dfs(v,des,min(edge[i].cap,flow-res));
     59       if (tmp<=0) continue;
     60       res+=tmp;
     61       edge[i^1].cap+=tmp;
     62       edge[i].cap-=tmp;
     63       if (res==flow) return res;
     64     }
     65   return res;
     66 }
     67 int main()
     68 {int S,T,i,j;
     69   cin>>n>>m;
     70   S=0;T=n*m+1;
     71   memset(head,-1,sizeof(head));
     72   for (i=1;i<=n;i++)
     73     {
     74       for (j=1;j<=m;j++)
     75     {
     76       id[i][j]=++cnt;
     77       scanf("%d",&a[i][j]);
     78     }
     79     }
     80   for (i=1;i<=n;i++)
     81     {
     82       for (j=1;j<=m;j++)
     83     {
     84       if (a[i][j]==1) add(S,id[i][j],inf);
     85       else if (a[i][j]==2) add(id[i][j],T,inf);
     86       if (a[i][j]!=2)
     87         {
     88           if (i-1&&a[i-1][j]!=1) add(id[i][j],id[i-1][j],1);
     89           if (j-1&&a[i][j-1]!=1) add(id[i][j],id[i][j-1],1);
     90           if (i+1<=n&&a[i+1][j]!=1) add(id[i][j],id[i+1][j],1);
     91           if (j+1<=m&&a[i][j+1]!=1) add(id[i][j],id[i][j+1],1);
     92         }
     93     }
     94     }
     95   while (bfs(S,T))
     96     {
     97       int x=0;
     98       memcpy(cur,head,sizeof(cur));
     99       while (x=dfs(S,T,inf)) ans+=x;
    100     }
    101   cout<<ans;
    102 }
  • 相关阅读:
    MFC知识点总结
    fopen函数打开文件总是返回NULL错误
    四.Windows I/O模型之重叠IO(overlapped)模型
    三.Windows I/O模型之事件选择(WSAEventSelect )模型
    二.Windows I/O模型之异步选择(WSAAsyncSelect)模型
    6.openldap客户端安装
    5.openldap设置用户本身修改密码
    4.openldap创建索引
    3.openldap生成LDAP用户
    2.openldap安装
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8506255.html
Copyright © 2020-2023  润新知