BZOJ1001[BeiJing2006]狼抓兔子最小割網絡流

Description

现在小朋友们最喜欢的”喜羊羊与灰太狼”,话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
enter image description here
左上角点为(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

Solution

最小割–>網絡流水題
Dinic中的剪枝優化一定要用全. 三個優化都已經在代碼中標明.

#include<cstdio>
#include<cctype>
#include<cstring>
#include<climits>
#include<algorithm>
using namespace std;
inline int read()
{
    int x = 0, flag = 1;;
    char c;
    while(! isgraph(c = getchar()))
        if(c == '-')
            flag *= - 1;
    while(isgraph(c))
        x = x * 10 + c - '0', c = getchar();
    return x * flag;
}
void print(int x)
{
    if(x < 0)
        putchar('-'), x *= - 1;
    if(x == 0)
        putchar('0');
    int ans[10], top = 0;
    while(x)
        ans[top ++] = x % 10, x /= 10;
    for(; top; top --)
        putchar(ans[top - 1] + '0');
}
const int oo = INT_MAX;
const int MAXN = 1 << 10, MAXM = 1 << 10;
int top;
struct Edge
{
    int v, flow, next;
    Edge(){}
    Edge(int v, int flow, int next): v(v), flow(flow), next(next){}
}G[MAXN * MAXM << 3];
int head[MAXN * MAXM];
void add_edge(int u, int v, int flow)
{
    G[top] = Edge(v, flow, head[u]);
    head[u] = top ++;
}
int Q[MAXN * MAXM];
int dep[MAXN * MAXM];
inline int BFS(int s, int t)
{
    int L = 0, R = 1;
    Q[L] = s;
    memset(dep, - 1, sizeof(dep));
    dep[s] = 0;
    while(L < R)
    {
        int u = Q[L];
        for(int i = head[u]; i != - 1; i = G[i].next)
            if(dep[G[i].v] == - 1 && G[i].flow)
            {
                dep[G[i].v] = dep[u] + 1, Q[R ++] = G[i].v;
                if(G[i].v == t)     //優化③ 
                    return 1;
            }
        L ++;
    }
    return 0; 
}
inline int DFS(int u, int flow, int t)
{
    if(u == t)
        return flow;
    int flow_sum = 0;
    for(int i = head[u]; i != - 1; i = G[i].next)
    {
        int v = G[i].v;
        if(G[i].flow && dep[v] == dep[u] + 1)
        {
            int cur_flow = min(G[i].flow, flow - flow_sum);
            cur_flow = DFS(v, cur_flow, t);
            flow_sum += cur_flow;
            G[i].flow -= cur_flow;
            G[i ^ 1].flow += cur_flow;
            if(flow_sum == flow)    //優化②, 也是最主要的優化 
                return flow; 
        }
    }
    if(! flow_sum)  //優化① 
        dep[u] = - 1; 
    return flow_sum;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("BZOJ1001.in", "r", stdin);
    freopen("BZOJ1001.out", "w", stdout);
    #endif
    int n = read(), m = read();
    top = 0;
    memset(head, - 1, sizeof(head));
    for(int i = 0; i < n; i ++)
        for(int j = 1; j < m; j ++)
        {
            int flow = read();
            add_edge(i * m + j, i * m + j - 1, flow),
            add_edge(i * m + j - 1, i * m + j, flow);
        }
    for(int i = 1; i < n; i ++)
        for(int j = 0; j < m; j ++)
        {
            int flow = read();
            add_edge(m * i + j, m * (i - 1) + j, flow);
            add_edge(m * (i - 1) + j, m * i + j, flow);
        }
    for(int i = 1; i < n; i ++)
        for(int j = 1; j < m; j ++)
        {
            int flow = read();
            add_edge(m * i + j, m * (i - 1) + j - 1, flow);
            add_edge(m * (i - 1) + j - 1, m * i + j, flow);
        }
    int flow = 0;
    while(BFS(0, n * m - 1))
        flow += DFS(0, oo, n * m - 1);
    print(flow);
}
posted @ 2017-01-19 08:50  Zeonfai  阅读(443)  评论(0编辑  收藏  举报