H.Escaping | |||||
| |||||
Description | |||||
One day, Large cruise ”Wu Kong” at sea. The station is represented by a square n*n divided into 1*1 blocks. Unfortunately , ” Wu Kong” hit an iceberg .It will sink after t minutes ,then every people die. However, there will be some life-saving equipment in some rooms(not only one), People from one room to reach another adjacent room (only four) needs one minute .If the people on board to get these life-saving devices so that they will survive, find the greatest number of people can survive. | |||||
Input | |||||
The first line contains two integers n and t (2≤n≤10, 1≤t≤10). Each of the next n lines contains n integers(0<=A[i][j]<=9).the people number at this time. Each of the next n more lines contains n integers, Indicates that the room have the number of life-saving equipment(0<=B[i][j]<=9). | |||||
Output | |||||
Print a single number — the maximum number of people who will be saved. | |||||
Sample Input | |||||
3 3 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 3 | |||||
Sample Output | |||||
2 | |||||
Author | |||||
Li jinmeng |
题目分析:
一个二部图:
前n*n个中有待逃生者的格子是一个点集;后n*n个有逃生船的格子是另一个点集;
本题为顶点有流量限制的最大流。因为是二部图,所以顶点上的流量限制可转移为新增的源点和汇点与这两部分点集连接的边上的流量限制。加边时,让源点与前一个点集之间的边流量为对应格子上的人数;后一个点集与汇点间的边流量为对应格子上的救生船数量。两个点集之间的边流量为正无穷大。
代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#define LL long long
#define db double
#define pi acos(-1.0)
#define mod
#define pr printf
#define fr(i,s,t) for(i=s;i<=t;++i)
#define N 220
#define E (N*N)
#define typec int
using namespace std;
int c[N][N];
int boat[N][N];
const typec inf = 0x3f3f3f3f;
struct edge { int x,y,nxt;typec c; } bf[E];
int ne,head[N], cur[N], ps[N], dep[N];
void Init();
void addedge(int x,int y,typec c);
typec flow(int n,int s,int t);
int main()
{
// freopen("h.in","r",stdin);
// freopen("output.txt","w",stdout);
int n,time,i,j;
int s = 217 ,t = 218;//增加一个源点和汇点
while(scanf("%d%d",&n,&time)!=EOF&&n)
{
Init();
for(i=0;i<n;++i)
for(j=0;j<n;++j)
{
scanf("%d",&c[i][j]);
if(c[i][j]>0)
addedge(s,i*n+j,c[i][j]);//汇点到第一个点集,流量限制为点上的人数
}
for(i=0;i<n;++i)
for(j=0;j<n;++j)
{
scanf("%d",&boat[i][j]);
if(boat[i][j]>0)
addedge(i*n+j+n*n,t,boat[i][j]);//第二个点集到汇点,流量限制为点上的救生船数
}
for(i=0;i<n;++i)
{
for(j=0;j<n;++j)
{
if(!c[i][j])
continue;
for(int i1=0;i1<n;++i1)
{
for(int j1=0;j1<n;++j1)
{
if(abs(i-i1)+abs(j-j1)>time||!boat[i1][j1])
continue;
addedge(i*n+j,i1*n+j1+n*n,inf);//两个点集之间的边,流量限制为正无穷
}
}
}
}
pr("%d\n",flow(N,s,t));
}
return 0;
}
void Init()
{
ne = 2 ;
memset(head,0,sizeof(head));
}
void addedge(int x,int y,typec c)
{
bf[ne].x = x; bf[ne].y = y; bf[ne].c = c;
bf[ne].nxt = head[x]; head[x] = ne++;
bf[ne].x = y; bf[ne].y = x; bf[ne].c = 0;
bf[ne].nxt = head[y]; head[y] = ne++;
}
typec flow(int n,int s,int t)
{
typec tr, res = 0;
int i,j,k,f,r,top;
while(1)
{
memset(dep,-1,n*sizeof(int));
for(f = dep[ps[0] = s] =0,r = 1;f != r;)
for(i = ps[f++], j = head[i]; j; j = bf[j].nxt )
{
if(bf[j].c&&-1==dep[k = bf[j].y])
{
dep[k] = dep[i] + 1;
ps[r++] = k;
if(k==t) {f = r; break;}
}
}
if(-1==dep[t]) break;
memcpy(cur,head,n*sizeof(int));
for(i = s,top = 0; ; )
{
if(i==t)
{
for(k=0,tr=inf;k<top;++k)
if(bf[ps[k]].c<tr)
tr = bf[ps[f=k]].c;
for(k=0;k<top;++k)
bf[ps[k]].c -= tr,bf[ps[k]^1].c +=tr;
res += tr;
i = bf[ps[top = f]].x;
}
for(j=cur[i];cur[i];j=cur[i]=bf[cur[i]].nxt)
if(bf[j].c&&dep[i]+1 == dep[bf[j].y]) break;
if(cur[i])
{
ps[top++] = cur[i];
i = bf[cur[i]].y;
}
else
{
if(0==top) break;
dep[i] = -1;i = bf[ps[--top]].x;
}
}
}
return res;
}