【HrbustOJ】Escaping(网络流,二部图)

H.Escaping
Time Limit: 1000 MSMemory Limit: 65536 K
Total Submit: 110 (26 users)Total Accepted: 23 (16 users)Special Judge: No
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 (2n10, 1t10). 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值