zoukankan      html  css  js  c++  java
  • BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】

    1001: [BeiJing2006]狼抓兔子

    Time Limit: 15 Sec  Memory Limit: 162 MB
    Submit: 23822  Solved: 6012
    [Submit][Status][Discuss]

    Description

    现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,
    而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

     

    左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 
    1:(x,y)<==>(x+1,y) 
    2:(x,y)<==>(x,y+1) 
    3:(x,y)<==>(x+1,y+1) 
    道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
    开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击
    这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,
    才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
    狼的数量要最小。因为狼还要去找喜羊羊麻烦.

    Input

    第一行为N,M.表示网格的大小,N,M均小于等于1000.
    接下来分三部分
    第一部分共N行,每行M-1个数,表示横向道路的权值. 
    第二部分共N-1行,每行M个数,表示纵向道路的权值. 
    第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 
    输入文件保证不超过10M

    Output

    输出一个整数,表示参与伏击的狼的最小数量.

    Sample Input

    3 4
    5 6 4
    4 3 1
    7 5 3
    5 6 7 8
    8 7 6 5
    5 5 5
    6 6 6

    Sample Output

    14

    HINT

     2015.4.16新加数据一组,可能会卡掉从前可以过的程序。

    Source

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001

    分析:最大流写法如下:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 int n,m;
      5 inline int read()
      6 {
      7     int x=0,f=1;
      8     char ch=getchar();
      9     while(ch<'0'||ch>'9')
     10     {
     11         if(ch=='-')
     12             f=-1;
     13         ch=getchar();
     14     }
     15     while(ch>='0'&&ch<='9')
     16     {
     17         x=x*10+ch-'0';
     18         ch=getchar();
     19     }
     20     return x*f;
     21 }
     22 inline void write(int x)
     23 {
     24     if(x<0)
     25     {
     26         putchar('-');
     27         x=-x;
     28     }
     29     if(x>9)
     30     {
     31         write(x/10);
     32     }
     33     putchar(x%10+'0');
     34 }
     35 int ne;
     36 const int N=1000010;
     37 struct data
     38 {
     39     int to,next,v;
     40 }e[N<<3];
     41 int head[N];
     42 int h[N],q[N],ans;
     43 inline void update(int u,int v,int w)
     44 {
     45     ne++;
     46     e[ne].to=v;
     47     e[ne].v=w;
     48     e[ne].next=head[u];
     49     head[u]=ne;
     50 }
     51 inline bool BFS()
     52 {
     53     int now,i;
     54     memset(h,-1,sizeof(h));
     55     int t=0,w=1;
     56     q[t]=1;
     57     h[1]=0;
     58     while(t<w)
     59     {
     60         now=q[t];
     61         t++;
     62         i=head[now];
     63         while(i)
     64         {
     65             if(e[i].v&&h[e[i].to]<0)
     66             {
     67                 q[w++]=e[i].to;
     68                 h[e[i].to]=h[now]+1;
     69             }
     70             i=e[i].next;
     71         }
     72     }
     73     if(h[n*m]==-1)
     74         return false;
     75     return true;
     76 }
     77 inline int DFS(int x,int f)
     78 {
     79     if(x==n*m)
     80         return f;
     81     int i=head[x];
     82     int w,used=0;
     83     while(i)
     84     {
     85         if(e[i].v&&h[e[i].to]==h[x]+1)
     86         {
     87             w=f-used;
     88             w=DFS(e[i].to,min(w,e[i].v));
     89             e[i].v-=w;
     90             e[i+1].v+=w;
     91             used+=w;
     92             if(used==f)
     93                 return f;
     94         }
     95         i=e[i].next;
     96     }
     97     if(!used)
     98         h[x]=-1;
     99     return used;
    100 }
    101 inline void dinic()
    102 {
    103     while(BFS())
    104     {
    105         ans+=DFS(1,0x7f7f7f7f);
    106     }
    107 }
    108 int main()
    109 {
    110     n=read();
    111     m=read();
    112     int x;
    113     for(int i=1;i<=n;i++)
    114     {
    115         for(int j=1;j<m;j++)
    116         {
    117             x=read();
    118             update(m*(i-1)+j,m*(i-1)+j+1,x);
    119             update(m*(i-1)+j+1,m*(i-1)+j,x);
    120         }
    121     }
    122     for(int i=1;i<n;i++)
    123     {
    124         for(int j=1;j<=m;j++)
    125         {
    126             x=read();
    127             update(m*(i-1)+j,m*(i)+j,x);
    128             update(m*(i)+j,m*(i-1)+j,x);
    129         }
    130     }
    131     for(int i=1;i<n;i++)
    132     {
    133         for(int j=1;j<m;j++)
    134         {
    135             x=read();
    136             update(m*(i-1)+j,m*(i)+j+1,x);
    137             update(m*(i)+j+1,m*(i-1)+j,x);
    138         }
    139     }
    140     dinic();
    141     write(ans);
    142     return 0;
    143 }

    分析:最小割,上网看了别人的博客,学习到了s-t平面图的最小割的解法,把原图中的面看作点,起点和终点都等同于最外面的那一个面,原图中一条边权值为w,新图中就等同于此边在平面图中分割开的两个面(即新图中两个点)连一条边,权值为w。建模完成后,新图中的起点和终点的一条路径就穿插过原图的一些边,即一条路径等于原图中的一个割,所以最小割就等于新图的最短路径长度。确实很厉害。

    推荐文章:浅析最大最小定理在信息学竞赛中的应用》--周冬

    下面给出SPFA+最小割代码:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 inline int read()
      5 {
      6     int x=0,f=1;
      7     char ch=getchar();
      8     while(ch<'0'||ch>'9')
      9     {
     10         if(ch=='-')
     11             f=-1;
     12         ch=getchar();
     13     }
     14     while(ch>='0'&&ch<='9')
     15     {
     16         x=x*10+ch-'0';
     17         ch=getchar();
     18     }
     19     return x*f;
     20 }
     21 inline void write(int x)
     22 {
     23     if(x<0)
     24     {
     25         putchar('-');
     26         x=-x;
     27     }
     28     if(x>9)
     29     {
     30         write(x/10);
     31     }
     32     putchar(x%10+'0');
     33 }
     34 #define M 2000001
     35 int n,m,nm;
     36 struct data
     37 {
     38     int to,next,v;
     39 }e[4*M];
     40 int dis[M],q[M],head[M];
     41 bool flag[M];
     42 int ne;
     43 inline void update(int u,int v,int w)
     44 {
     45     ne++;
     46     e[ne].to=v;
     47     e[ne].v=w;
     48     e[ne].next=head[u];
     49     head[u]=ne;
     50     ne++;
     51     e[ne].to=u;
     52     e[ne].v=w;
     53     e[ne].next=head[v];
     54     head[v]=ne;
     55 }
     56 inline void spfa()
     57 {
     58     memset(dis,0x3f,sizeof(dis));
     59     int i,t=0,w=1;
     60     dis[0]=q[w]=0;flag[0]=1;
     61     while(t!=w)
     62     {
     63         int u=q[t++];
     64         flag[u]=0;
     65         if(t==M)t=0;
     66         for(int i=head[u];i;i=e[i].next)
     67         {
     68             int v=e[i].to;
     69             if(dis[v]>dis[u]+e[i].v)
     70             {
     71                 dis[v]=dis[u]+e[i].v;
     72                 if(flag[v]==0)
     73                 {
     74                     flag[v]=1;
     75                     q[w++]=v;
     76                     if(w==M)w=0;
     77                 }
     78             }
     79         }
     80     }
     81 }
     82 int main()
     83 {
     84     n=read();
     85     m=read();
     86     nm=(n*m-m-n+1)<<1;
     87     int x;
     88     for(int j=1;j<m;j++)
     89     {
     90         x=read();
     91         update(j,nm+1,x);
     92     }
     93     for(int i=1;i<n-1;i++)
     94     {
     95         for(int j=1;j<m;j++)
     96         {
     97             x=read();
     98             update((i<<1)*(m-1)+j,((i<<1)-1)*(m-1)+j,x);
     99         }
    100     }
    101     for(int j=1;j<m;j++)
    102     {
    103         x=read();
    104         update(0,((n<<1)-3)*(m-1)+j,x);
    105     }
    106     for(int i=0;i<n-1;i++)
    107     {
    108         for(int j=1;j<=m;j++)
    109         {
    110             x=read();
    111             if(j==1)
    112                 update(0,(i<<1)*(m-1)+m,x);
    113             else if(j==m)
    114                 update((i<<1|1)*(m-1),nm+1,x);
    115             else
    116                 update((i<<1)*(m-1)+j-1,(i<<1)*(m-1)+j+m-1,x);
    117         }
    118     }
    119     for(int i=0;i<n-1;i++)
    120     {
    121         for(int j=1;j<m;j++)
    122         {
    123             x=read();
    124             update((i<<1|1)*(m-1)+j,(i<<1)*(m-1)+j,x);
    125         }
    126     }
    127     spfa();
    128     write(dis[nm+1]);
    129     return 0;
    130 }
  • 相关阅读:
    9. 如何在控制器或模型中获取当前登录的管理员或登录用户信息
    FastAdmin控制管理员只显示自己添加的数据
    div 隐藏
    使用JavaScript实现Input输入数据后自动计算并实时显示
    thinkphp中在页面怎么格式输出小数和时间
    fastadmin表单提交提示红色OK
    在某个域被使用或改变时,它会改变颜色。【用于提示表单已填充】
    Unix命令行学习
    Ubuntu菜鸟入门(十)—— Flash控件安装
    Ubuntu菜鸟入门(九)—— 支付宝支付控件安装
  • 原文地址:https://www.cnblogs.com/ECJTUACM-873284962/p/7412829.html
Copyright © 2011-2022 走看看