zoukankan      html  css  js  c++  java
  • [BZOJ1001][BeiJing2006]狼抓兔子(最小割转最短路|平面图转对偶图)

    1001: [BeiJing2006]狼抓兔子

    Time Limit: 15 Sec  Memory Limit: 162 MB
    Submit: 31805  Solved: 8494
    [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新加数据一组,可能会卡掉从前可以过的程序。

    Solution

      一眼一个最小割。以为可以复习一下板子了,可以看这边数N*N*3不对呀,直接跑最小割会炸的。

      于是就翻题解学到了平面图转对偶图的神奇操作。

      平面图可以参考这篇博文 https://www.cnblogs.com/lfri/p/9939463.html

      平面图转对偶图的方法可以参考这篇博文 https://www.cnblogs.com/qzqzgfy/p/5578785.html

      像题目中这种源点和汇点在无界面的边界上的平面图叫做s-t平面图

      在这种图上可以实现求最小割转求最短路。

      需要注意的是实际操作时要先把s到t连条虚边,把原图的边界的面分成两个部分,也就是说多了一个附加面作为s。

      实现时主要是要给每个面(也就是对偶图中的点)编好号,代码中有注释。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> pi;
    //注意空间要开够 
    const int N=1005*1005*2;
    inline int read(){
        int x=0,w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return w?-x:x;
    }
    struct edge{
        int v,w,last;
    }e[N*3];
    int tot,tail[N];
    inline void add(int x,int y,int z){
        e[++tot]=(edge){y,z,tail[x]};
        tail[x]=tot;
        e[++tot]=(edge){x,z,tail[y]};
        tail[y]=tot;
    }
    int n,m,s,t,base;
    //一个小正方形的下三角为(i-1)*(m-1)+j,上三角加个base
    bool check(int i,int j){return i>=1&&i<=n-1&&j>=1&&j<=m-1;} 
    int down(int i,int j){return check(i,j)?(i-1)*(m-1)+j:s;}
    int up(int i,int j){return check(i,j)?down(i,j)+base:t;}
    void build(){
        s=0,base=(n-1)*(m-1),t=base<<1|1;
        //原平面图的面有(n-1)*(m-1)*2+1个,再加个编号为0的附加面
        for(int i=1;i<=n;++i)
            for(int j=1;j<m;++j)
                add(down(i-1,j),up(i,j),read());
        for(int i=1;i<n;++i)
            for(int j=1;j<=m;++j)
                add(up(i,j-1),down(i,j),read());
        for(int i=1;i<n;++i)
            for(int j=1;j<m;++j)
                add(up(i,j),down(i,j),read());
    }
    //这只是一个普通的堆优化dijkstra 
    bool vis[N];
    int d[N];
    void dij(){
        priority_queue<pi,vector<pi>,greater<pi> > q;
        memset(d,0x3f,sizeof d);d[s]=0;
        q.push(make_pair(d[s],s));
        while(!q.empty()){
            int x=q.top().second;q.pop();
            if(vis[x]) continue;vis[x]=true;
            for(int p=tail[x];p;p=e[p].last){
                int &y=e[p].v,&w=e[p].w;
                if(d[y]>d[x]+w){
                    d[y]=d[x]+w;
                    q.push(make_pair(d[y],y));
                }
            }
        }
    }
    int main(){
        n=read(),m=read();
        build();dij();
        cout<<d[t]<<endl;
        return 0;
    }
    BZOJ1001
  • 相关阅读:
    005.Kickstart部署多系统
    004.Kickstart部署之FTP架构
    003.Kickstart部署之HTTP架构
    C#并发编程之异步编程(二)
    设计模式之策略者模式
    设计模式之职责链模式
    C#并发编程之异步编程(一)
    C#并发编程之概述
    微服务探索与实践—总述
    设计模式之模板方法模式
  • 原文地址:https://www.cnblogs.com/gosick/p/11251975.html
Copyright © 2011-2022 走看看