题目大意: 给定一个n*n的图,给定一些点中的人数,给定一个逃生时间,再给定一个有一定救援物资的房间分布图,一个房间的人移动到另一个房间需要一个单位的时间,求给定时间内最多能救多少人.
考试的时候真不知道这是个网络流的问题,对于图论题还是不能准确的建模,能记住几个常用的模型也好啊T_T 结果就和逼哥一起写模拟程序,对于每个人,选定他能跑到最远的那个救生舱,直到救生舱的救援物资为0。然后又是结构体又是排序又是一大堆循环和控制条件,写完后竟然还能把样例和自己举的例都过了哈哈哈哈,结果提交还是错的,应该还是被卡住了……还得多练图论题,模型真的很重要,算法知道建不出模型就很呆……
题解:这就是刘汝佳白书上网络流常见模型的第一种:多源多汇模型。
建立一个超级源点和超级汇点,将所有有人的房间和超级源点相连,流量就是人数,将所有救援房间和超级汇点相连,流量就是救援物资数,再将曼哈顿距离小于等于t的人房间和救援物资房间相连,就构成一张标准的网络流。用bfs增广,dfs计算最大流,得到答案。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define sc scanf
#define pr printf
#define fr(i,t,n) for(int i = t ; i <= n ; i++)
#define re return
#define ct continue
#define br break
#define me(a,t) memset(a,t,sizeof(a))
using namespace std;
/*
网络流多源多汇的基本模型,建立超级源点和超级汇点
问题就演变成从源点到汇点的最大流
*/
const int maxn = 220;
const int maxm = maxn*maxn;
const int src = 0;
const int sink = maxn - 1;
const int inf = 1e8;
int ec,head[maxn],a[maxn][maxn],b[maxn][maxn],begx,begy;
int n ,t,id[maxn][maxn];
struct node
{
int u,v,nt,w;
}ed[maxm];
void add(int a , int b , int cap)
{
ed[++ec].u = a;
ed[ec].v = b;
ed[ec].nt = head[a];
ed[ec].w = cap;
head[a] = ec;
ed[++ec].u = b;
ed[ec].v = a;
ed[ec].nt = head[b];
ed[ec].w = 0;
head[b] = ec;
}
void init()
{
ec = -1;
me(head,-1);
fr(i,1,n)
fr(j,1,n)
{
sc("%d",&a[i][j]);
id[i][j] = (i-1)*n+j;
if(a[i][j] > 0)add(src,id[i][j],a[i][j]);//建立所有有人的房间和超级源点的边
}
fr(i,1,n)
fr(j,1,n)
{
sc("%d",&b[i][j]);
fr(k,1,n)
fr(l,1,n)
{
if(b[i][j]&&a[k][l] && abs(k-i)+abs(j-l) <= t)
add(id[k][l],id[i][j]+n*n,inf);//如果在t时间能够移动到救援房间,建立救援房间和人房间的边
}
if(b[i][j] > 0)add(id[i][j]+n*n,sink,b[i][j]);//建立救援房间和超级汇点的边
}
}
int q[maxn],lev[maxn];
//模拟队列,bfs寻找增广路
bool bfs()
{
int front = 0;
q[front] = src;
me(lev,-1);
lev[src] = 0;
while(front >= 0)
{
int x = q[front--];
for(int i = head[x] ; i != -1 ; i = ed[i].nt)
{
if(ed[i].w > 0 && lev[ed[i].v] == -1)
{
lev[ed[i].v] = lev[x] + 1;
if(ed[i].v == sink)re 1;
q[++front] = ed[i].v;
}
}
}
re 0;
}
int work[maxn];
//dfs利用增广路计算最大流
int dfs(int x , int maxc)
{
if(x == sink) re maxc;
int ret = 0 , flow;
for(int i = work[x] ; i != -1 ; i = ed[i].nt)
{
work[x] = i;
if(lev[ed[i].v] == lev[x] + 1 && ed[i].w > 0)
{
flow = dfs(ed[i].v,min(maxc - ret , ed[i].w));
ret += flow;
ed[i].w -= flow;
ed[i^1].w += flow;
if(ret == maxc)re maxc;
}
}
re ret;
}
int gao()
{
int res = 0;
while(bfs())
{
fr(i,0,sink)work[i]=head[i];
res += dfs(src,inf);
}
re res;
}
int main()
{
//freopen("H.in","r",stdin);
//freopen("H1.out","w",stdout);
while(sc("%d%d",&n,&t) != EOF)
{
init();
// cout<" "<"%d\n",gao());
}
}