【BZOJ】1001: [BeiJing2006]狼抓兔子

1001: [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

讲讲Dinic算法:(Dinic算法属于最短增广路中的一种)

层次图:每次在残量网络中BFS得到每点到起点的距离;路径是在层次中找的,即d[v] == d[x]+1;比EK算法更高效

优化1:在DFS里面并不是每次只走一条路径,而是DFS到一条最短路之后,在回溯到不含最短边继续搜索;在DFS里面a表示目前为止所有弧的最小残量;而f表示路径的流量;即f<=a;根据a -= f是否等于0来判断是在当前节点几次上继续搜索还是回溯;

优化2:因为一个点可能会被多次搜索到,所以记录下前面搜索到该节点的那条边的序号,这样就不会从头开始搜索了;

ps:图中是无向边,我竟然还是建了反向边cap为0的图,真是醉了;JMJST使用Djistra+heap只用了516ms;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<stack>
#include<set>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
#define inf 0x3f3f3f3f
template<typename T>
void read1(T &m)
{
    T x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    m = x*f;
}
template<typename T>
void read2(T &a,T &b){read1(a);read1(b);}
template<typename T>
void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
template<typename T>
void out(T a)
{
    if(a>9) out(a/10);
    putchar(a%10+‘0‘);
}
const int M = 1000*1010;
int head[M*6],tot;
struct edge{
    int from,to,cap,flow,Next;
}e[M*6];
void ins(int u,int v,int cap)
{
    e[tot].Next = head[u];
    e[tot].from = u;//为了t->s时由v推到u;
    e[tot].to = v;
    e[tot].cap = cap;
    e[tot].flow = 0;
    head[u] = tot++;
}
int vis[M],s,t,cur[M],d[M];
queue<int> Q;
int BFS()
{
    rep1(i,s,t) vis[i] = 0;
    vis[s] = 1;d[s] = 0;
    Q.push(s);
    while(!Q.empty()){
        int u = Q.front();Q.pop();
        for(int i = head[u];~i;i = e[i].Next){
            int v = e[i].to;
            if(!vis[v] && e[i].cap > e[i].flow){ // 只考虑残量网络的弧
                vis[v] = 1;
                d[v] = d[u] + 1;
                Q.push(v);
            }
        }
    }
    return vis[t];
}
int DFS(int x,int a)// a表示目前为止所有弧的最小残量
{
    if(x == t || a == 0) return a;
    int& i = cur[x];//回溯时会多次DFS到同一个点
    if(i == 0) i = head[x];
    int flow = 0, f;
    for(;~i;i = e[i].Next){// 从上次考虑的弧开始
        int v = e[i].to;
        if(d[v] == d[x]+1 && (f = DFS(v,min(a,e[i].cap - e[i].flow))) > 0){
            e[i].flow += f;
            e[i^1].flow -= f;
            flow += f;
            a -= f;// 残量-流量
            if(a == 0)   break;
        }
    }
    return flow;
}
int Dinic()
{
    int flow = 0;
    while(BFS()){//仍然存在增广路时再DFS
        rep1(i,s,t) cur[i] = 0;//记录当前探索到的点的弧的编号
        flow += DFS(s,inf);
    }
    return flow;
}
void input()
{
    int n,m,cost;
    read2(n,m);
    s = 0,t = n*m - 1;
    MS1(head);tot = 0;
    rep0(i,0,n){
        rep0(j,0,m-1){
            read1(cost);
            int u = i*m+j;
            ins(u,u+1,cost);ins(u+1,u,cost);
        }
    }
    rep0(i,0,n-1){
        rep0(j,0,m){
            read1(cost);
            int u = i*m+j,v = u + m;
            ins(u,v,cost);ins(v,u,cost);
        }
    }
    rep0(i,0,n-1){
        rep0(j,0,m-1){
            read1(cost);
            int u = i*m+j,v = u + m + 1;
            ins(u,v,cost);ins(v,u,cost);//无向边
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    input();
    out(Dinic());
    return 0;
}

时间: 2024-10-23 04:31:37

【BZOJ】1001: [BeiJing2006]狼抓兔子的相关文章

BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】

1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 23822  Solved: 6012[Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M

BZOJ 1001: [BeiJing2006]狼抓兔子 对偶图

本题是最大流转最小割转对偶图最短路 推荐周东的<浅析最大最小定理在信息学竞赛中的应用> 1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 12166  Solved: 2866 [Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在

BZOJ 1001: [BeiJing2006]狼抓兔子(最短路)

平面图的最小割转化为对偶图的最短路(资料:两极相通——浅析最大最小定理在信息学竞赛中的应用) ,然后DIJKSTRA就OK了. ------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<que

BZOJ 1001: [BeiJing2006]狼抓兔子 最小割

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)

BZOJ 1001 [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) 道路上的权值表示这条路上最多能够通过的兔子数,道路是

BZOJ 1001 [BeiJing2006]狼抓兔子

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 题意: ... 很容易想到求的是一个最小割=最大流. 之前一直用的刘汝佳的模板STL过题,很久没用过数组模拟了. 再次熟悉一下写法,first数组是索引数组,标记的结点的最后一条边,利用next数组找到上一条边. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 1100000 6 int n,m,

bzoj 1001: [BeiJing2006]狼抓兔子 平面图最小割

平面图跑最大流 可以转换为其对偶图跑最短路 一个环对应一个割  找到最小环(即最短路)极为所求,注意辅助边的建立 加入读入优化  不过时间还是一般  估计是dij写的不好   大神勿喷~~~ /************************************************************** Problem: 1001 User: 96655 Language: C++ Result: Accepted Time:1724 ms Memory:95120 kb ****

bzoj 1001: [BeiJing2006]狼抓兔子 最短路+对偶图

题意:求一个表格图的最小割. 分析:这题如果套上一个网络流的话是会挂的,所以我们要把该图转换成它的对偶图,具体方法可以参照两级相通----浅析最大最小定理在信息学竞赛中的应用 By 周冬.然后跑对短路就好了. 良心的出题人居然没卡spfa 这题要特判n=1 or m=1的情况 这次一开始无限12msWA的原因是spfa的结束条件是until head>=tail,而我用的是循环队列--不想多说,以后一定要注意才行啊. 代码: const maxn=2000009; var s,t,n,m,e:l

bzoj 1001 [BeiJing2006]狼抓兔子 最小割+最短路

题面 题目传送门 解法 将最大流转化成最小割,然后跑最短路即可 具体如何见图可以参考下图 尽量用dijkstra 代码 #include <bits/stdc++.h> #define PI pair <int, int> #define mp make_pair #define N 1010 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x