组队赛3——网络流——K——escaping

题目大意: 给定一个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());
    }
}

你可能感兴趣的:(图论)