• 【bzoj题解】1001 狼抓兔子


    题目描述

    现在小朋友们最喜欢"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
     左上角点为(1,1),右下角点为(N,M)(上图中N=3,M=4).有以下三种类型的道路
    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只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的的数量要最小。因为狼还要去找喜羊羊麻烦。
    输入
    第一行为N,M.表示网格的大小,N,M均小于等于1000。
    接下来分三部分
    第一部分共N行,每行M-1个数,表示横向道路的权值。
    第二部分共N-1行,每行M个数,表示纵向道路的权值。
    第三部分共N-1行,每行M-1个数,表示斜向道路的权值。
    输出
    输出一个整数,表示参与伏击的狼的最小数量。
    样例输入
    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
    样例输出
    14
    题解
    裸的最小割,我转了转最大流跑Dinic。
    记得连双向边。发现当前弧优化很优秀……
     1 #include<cstdio>
     2 #include<cstring>
     3 #define F(i,a,b) for(int i=a;i<=b;++i)
     4 #define F2(i,a,b) for(int i=a;i<b;++i)
     5 #define v(a,b) ((a-1)*m+b)
     6 int n,m,S,T;
     7 int h[1000001],nxt[6000001],to[6000001],cap[6000001],tot=1;
     8 inline void ins(int x,int y,int c){nxt[++tot]=h[x];to[tot]=y;cap[tot]=c;h[x]=tot;nxt[++tot]=h[y];to[tot]=x;cap[tot]=c;h[y]=tot;}
     9 int iter[1000001],lv[1000001],que[1000001],l,r;
    10 inline int Min(int p,int q){return p<q?p:q;}
    11 void init(){
    12     int x;
    13     scanf("%d%d",&n,&m); S=1, T=v(n,m);
    14     F(i,1,n) F2(j,1,m)
    15         scanf("%d",&x), ins(v(i,j),v(i,j+1),x);
    16     F2(i,1,n) F(j,1,m)
    17         scanf("%d",&x), ins(v(i,j),v(i+1,j),x);
    18     F2(i,1,n) F2(j,1,m)
    19         scanf("%d",&x), ins(v(i,j),v(i+1,j+1),x);
    20 }
    21 bool lvl(){
    22     memset(lv,0,sizeof lv);
    23     lv[S]=1; que[1]=S; l=r=1;
    24     int u;
    25     while(l<=r){
    26         u=que[l++];
    27         for(int i=h[u];i;i=nxt[i])
    28             if(cap[i]&&!lv[to[i]]) lv[to[i]]=lv[u]+1, que[++r]=to[i];
    29     } if(!lv[T]) return 0;
    30     F(i,S,T) iter[i]=h[i];
    31     return 1;
    32 }
    33 int flow(int u,int f){
    34     if(u==T) return f;
    35     int d,sum=0;
    36     for(int&i=iter[u];i;i=nxt[i]){
    37         if(cap[i]&&lv[to[i]]>lv[u]){
    38             d=flow(to[i],Min(cap[i],f));
    39             sum+=d; f-=d;
    40             cap[i]-=d; cap[i^1]+=d;
    41             if(!f) return sum;
    42         }
    43     }
    44     return sum;
    45 }
    46 int Dinic(){
    47     int sum=0;
    48     while(lvl())
    49         sum+=flow(S,999999999);
    50     return sum;
    51 }
    52 int main(){
    53     init();
    54     printf("%d",Dinic());
    55     return 0;
    56 }
  • 相关阅读:
    Best Practices for Using Alpha
    Android手机 Fildder真机抓包
    Android调用MediaScanner进行新产生的媒体文件扫描
    读书笔记-----Java并发编程实战(二)对象的共享
    项目经验谈---IM新消息界面刷新异常处理记录
    读书笔记-----Java并发编程实战(一)线程安全性
    OnScroll与OnTouchEvent方法的区别与联系
    View的getLeft, getRight, getTop, getBottom
    如何用DNS+GeoIP+Nginx+Varnish做世界级的CDN
    更改ubuntu mysql data目录位置
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/7327131.html
Copyright © 2020-2023  润新知