zoukankan      html  css  js  c++  java
  • BZOJ 1001 [BeiJing2006] 狼抓兔子(平面图最大流)

     

    题目大意

     

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

    左上角点为 (1, 1),右下角点为 (N, M) (上图中N=4, 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 均小于等于 1000

    做法分析

     

    一看就是最小割问题,写的比较好的网络流可以直接暴力的搞过去,当然,正解肯定不是这样,虽然是一个水题,不过还是值得一做的

    这题需要利用平面图的对偶图性质

    平面图的对偶图很好构造:

      将原图中的面变成新图中的点

      原图中,每条边必定分割了两个面,在新图中,对应的点之间添加一条边,边权还是原图中边的边权

    在原图中的一个全局的割就对应了新图中的一个环,也就是说,如果想要求原图中的一个全局最小割,只需要在新图中找一个最小环即可

    怎么求出原图中分割固定点 s 和 t(s 和 t 处于一个无线大的平面的边缘) 的一个最小割呢?

      先在原图中添加 s 到 t 的边,给原图增加了一个面

      构造原图的对偶图,把由于增边而增加的新面对应的点设为 S,无穷大的平面对应的点设为 T

      删掉对偶图中 S 到 T 直接相连的边

      求出 S 到 T 的最短路就可以了

    详细请看周冬的论文 《两极相通——浅析最大—最小定理在信息学竞赛中的应用》

    这题按照上面将的建图,跑最短路就行了,听说 SPFA 也能过,我没试过,用的堆优化的 Dijkstra + 输入外挂直接 516ms 过掉

    参考代码

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 #include <queue>
      5 
      6 using namespace std;
      7 
      8 const int N=2000006, INF=0x3fffffff, E=N*3;
      9 
     10 struct ARC {
     11     int u, val, next;
     12     inline void init(int a, int b, int c) {
     13         u=a, val=b, next=c;
     14     }
     15 } arc[E];
     16 int head[N], tot, S, T, n, m, dis[N];
     17 bool vs[N];
     18 
     19 struct data {
     20     int u, dis;
     21     data() {}
     22     data(int a, int b) : u(a), dis(b) {}
     23     bool operator < (const data &T) const {
     24         return dis>T.dis;
     25     }
     26 };
     27 
     28 inline void add_arc(int s, int t, int val) {
     29     arc[tot].init(t, val, head[s]);
     30     head[s]=tot++;
     31 }
     32 
     33 priority_queue <data> Q;
     34 void Dijkstra() {
     35     fill(dis, dis+T+1, INF);
     36     fill(vs, vs+T+1, 0);
     37     while(!Q.empty()) Q.pop();
     38     dis[S]=0, Q.push(data(S, 0));
     39     for(int u; !Q.empty(); ) {
     40         u=Q.top().u, Q.pop();
     41         if(vs[u]) continue;
     42         if(u==T) {
     43             printf("%d
    ", dis[T]);
     44             break;
     45         }
     46         vs[u]=1;
     47         for(int e=head[u]; e!=-1; e=arc[e].next) {
     48             int v=arc[e].u;
     49             if(vs[v] || dis[u]+arc[e].val>=dis[v]) continue;
     50             dis[v]=dis[u]+arc[e].val;
     51             Q.push(data(v, dis[v]));
     52         }
     53     }
     54 }
     55 
     56 void read(int &x) {
     57     char c;
     58     while((c=getchar())<'0' || c>'9');
     59     x=c-'0';
     60     while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
     61 }
     62 
     63 void Input() {
     64     for(int i=0, id1, id2, a; i<=n-1; i++)
     65         for(int j=1; j<=m-1; j++) {
     66             read(a);
     67             id1=((i-1)*(m-1)+j)*2-1;
     68             id2=(i*(m-1)+j)*2;
     69             if(i==0) id1=T;
     70             else if(i==n-1) id2=S;
     71             add_arc(id1, id2, a);
     72             add_arc(id2, id1, a);
     73         }
     74 
     75     for(int i=1, id1, id2, a; i<=n-1; i++)
     76         for(int j=0; j<m; j++) {
     77             read(a);
     78             id1=((i-1)*(m-1)+j)*2;
     79             id2=((i-1)*(m-1)+j+1)*2-1;
     80             if(j==0) id1=S;
     81             else if(j==m-1) id2=T;
     82             add_arc(id1, id2, a);
     83             add_arc(id2, id1, a);
     84         }
     85 
     86     for(int i=1, id1, id2, a; i<=n-1; i++)
     87         for(int j=1; j<=m-1; j++) {
     88             read(a);
     89             id1=((i-1)*(m-1)+j)*2;
     90             id2=((i-1)*(m-1)+j)*2-1;
     91             add_arc(id1, id2, a);
     92             add_arc(id2, id1, a);
     93         }
     94 }
     95 
     96 int main() {
     97     read(n), read(m);
     98     S=0, T=(n-1)*(m-1)*2+1;
     99     fill(head, head+T+1, -1), tot=0;
    100     if(n==1 || m==1) {
    101         if(n>m) swap(n, m);
    102         int ans=INF;
    103         for(int i=1, a; i<m; i++) {
    104             read(a);
    105             if(ans>a) ans=a;
    106         }
    107         printf("%d
    ", ans==INF?0:ans);
    108     }
    109     else Input(), Dijkstra();
    110     return 0;
    111 }
    BZOJ 1001

    题目链接 & AC 通道

    BZOJ 1001 [BeiJing2006] 狼抓兔子

  • 相关阅读:
    关于PHP高并发抢购系统设计
    阿里云服务器带宽跑满怎么办
    DedeCMS数据负载性能优化方案简单几招让你提速N倍
    linux===启动sdk manager下载配置sdk的时候报错的解决办法
    linux===linux后台运行和关闭、查看后台任务(转)
    自动化测试===热门开源自动化测试框架
    python实战===图片转换为字符的源码(转)
    移动端测试===安卓设备共享程序-发布版本“share device”
    MACACA===gradle下载和安装
    jython
  • 原文地址:https://www.cnblogs.com/zhj5chengfeng/p/3273531.html
Copyright © 2011-2022 走看看