[BZOJ1001][BeiJing2006]狼抓兔子

[BeiJing2006]狼抓兔子

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 :
一看就是最小割问题,写的比较好的网络流可以直接暴力的搞过去,当然,正解肯定不是这样,虽然是一个水题,不过还是值得一做的
这题需要利用平面图的对偶图性质
平面图的对偶图很好构造:
  将原图中的面变成新图中的点
  原图中,每条边必定分割了两个面,在新图中,对应的点之间添加一条边,边权还是原图中边的边权
在原图中的一个全局的割就对应了新图中的一个环,也就是说,如果想要求原图中的一个全局最小割,只需要在新图中找一个最小环即可
怎么求出原图中分割固定点 s 和 t(s 和 t 处于一个无线大的平面的边缘) 的一个最小割呢?
  先在原图中添加 s 到 t 的边,给原图增加了一个面
  构造原图的对偶图,把由于增边而增加的新面对应的点设为 S,无穷大的平面对应的点设为 T
  删掉对偶图中 S 到 T 直接相连的边
  求出 S 到 T 的最短路就可以了

Code :

#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define tr(p, u) for (Node *p = g[u]; p; p = p->nxt)
#define fst first
#define sec second
#define MS(_, __) memset(_, (__), sizeof(_))
#define PB push_back
#define MP make_pair

template<typename T> inline void read(T &x){
    x = 0; T f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
    x *= f;
}

const int N = 2222222;
struct Node{int v, c; Node *nxt;}pool[N*3], *tail=pool, *g[N];
int n, m, size, S, T;
inline int mapping(int x, int y, int t){return (t-1)*size+(x-1)*m+y;}
inline void addedge(int u, int v, int c){
    tail->v = v; tail->c = c; tail->nxt = g[u]; g[u] = tail++;
}
inline int dijkstra(){
    __gnu_pbds::priority_queue<PII, greater<PII> > q;
    static int dist[N]; static bool vis[N];
    MS(dist, 0x7f); MS(vis, 0);
    dist[S] = 0; q.push(MP(0, S));
    while (!q.empty()){
        PII now = q.top(); q.pop();
        if (vis[now.sec]) continue; vis[now.sec] = 1;
        tr(p, now.sec) if (dist[p->v] > dist[now.sec] + p->c){
            dist[p->v] = dist[now.sec] + p->c;
            q.push(MP(dist[p->v], p->v));
        }
    }
    return dist[T];
}
int main(){
    read(n); read(m); n--; m--;
    size = n*m;
    S = 0; T = 2 * size + 1;
    rep(i, 1, n+1) rep(j, 1, m){
        int t; read(t);
        if (i == 1) addedge(mapping(i, j, 1), T, t);
        else if (i > n) addedge(S, mapping(n, j, 2), t);
        else{
            addedge(mapping(i, j, 1), mapping(i-1, j, 2), t);
            addedge(mapping(i-1, j, 2), mapping(i, j, 1), t);
        }
    }
    rep(i, 1, n) rep(j, 1, m+1){
        int t; read(t);
        if (j == 1) addedge(S, mapping(i, j, 2), t);
        else if (j > m) addedge(mapping(i, m, 1), T, t);
        else{
            addedge(mapping(i, j-1, 1), mapping(i, j, 2), t);
            addedge(mapping(i, j, 2), mapping(i, j-1, 1), t);
        }
    }
    rep(i, 1, n) rep(j, 1, m){
        int t; read(t);
        addedge(mapping(i, j, 1), mapping(i, j, 2), t);
        addedge(mapping(i, j, 2), mapping(i, j, 1), t);
    }
    printf("%d\n", dijkstra());
    return 0;          
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值