题目描述
现在小朋友们最喜欢的”喜羊羊与灰太狼”,话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
左上角点为(1,1),右下角点为(N,M)(上图中N=3,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.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值.
第二部分共N-1行,每行M个数,表示纵向道路的权值.
第三部分共N-1行,每行M-1个数,表示斜向道路的权值.
输出格式:
输出一个整数,表示参与伏击的狼的最小数量.
输入样例:
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
输出样例:
14
分析
按题意,本题求该网络的最小割
根据最大流最小割定理可知:最小割 = 最大流,因此,直接跑网络流把,不过本题由于数据量较大,需要做出些优化,比如建边(相对蓝书的模板而言)
PS:本题还有更快的方法(对偶图+最短路),对此不做探究
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#define IL inline
#define INF 0x7f7f7f7f
using namespace std;
inline int read()
{
char c=getchar();
int sum=0,k=1;
for(;'0'>c || c>'9';c=getchar())
if(c=='-') k=-1;
for(;'0'<=c && c<='9';c=getchar()) sum=sum*10+c-'0';
return sum*k;
}
int S, T;
struct Edge
{
int to, nxt;
int flow;
Edge(int v = 0, int nxt_ = 0, int f = 0)
{
to = v; nxt = nxt_; flow = f;
}
}edge[6000000];
int last[1000005];
int cnt;
IL void add(int u, int v, int f)
{
edge[cnt] = Edge(v, last[u], f); last[u] = cnt++;
edge[cnt] = Edge(u, last[v], f); last[v] = cnt++; // 此处可以理解为将原本要添加的四条边两两合并
}
int dep[1000005];
int cur[1000005];
IL int min_(int x, int y) { return x < y ? x : y ; }
IL bool Bfs()
{
memset(dep, 0, sizeof(dep));
queue<int>Q;
dep[S] = 1;
Q.push(S);
for(int t = 1, u; t;)
{
u = Q.front(); Q.pop(); --t;
for(int i = last[u]; i != -1; i = edge[i].nxt)
if(!dep[edge[i].to] && edge[i].flow)
{
dep[edge[i].to] = dep[u] + 1;
Q.push(edge[i].to); ++t;
}
}
return dep[T];
}
IL int Dfs(int u, int a)
{
if(u == T || !a) return a;
int flow = 0, f;
for(int &i = cur[u]; i != -1; i = edge[i].nxt)
if(dep[edge[i].to] == dep[u] + 1 && edge[i].flow)
if((f = Dfs(edge[i].to, min_(a, edge[i].flow))) > 0)
{
edge[i].flow -= f;
edge[i ^ 1].flow += f;
flow += f;
if(!(a -= f)) return flow;
}else
dep[edge[i].to] = -1;
return flow;
}
IL int maxflow()
{
int flow = 0;
for(; Bfs();)
{
for(int i = S; i <= T; ++i) cur[i] = last[i];
flow += Dfs(S, INF);
}
return flow;
}
int main()
{
int n = read(), m = read(), w;
S = 1; T = n * m;
memset(last, -1, sizeof(last));
for(int i = 1, k = 1; i <= n; ++i, ++k)
for(int j = 1; j < m; ++j, ++k)
add(k, k + 1, read());
for(int i = 1, k = 1; i < n; ++i)
for(int j = 1; j <= m; ++j, ++k)
add(k, k + m, read());
for(int i = 1, k = 1; i < n; k = i * m + 1, ++i)
for(int j = 1; j < m; ++j, ++k)
add(k, k + m + 1, read());
printf("%d\n",maxflow());
return 0;
}