网络流:HDU 2732

HDU 2732

hdu 2732


题意:给你两个值n,d,给你两张图,都是n行,第一个图每个位置上的值q表示对应点的柱子的坚硬程度,表示这个柱子最多允许q只蜥蜴从这里跳出去,等于0就说明这个地方没有柱子,每个柱子最多容纳一只蜥蜴。第二个图有两个值一时’L’表示这个地方有一只蜥蜴,’.'表示这个地方是没有蜥蜴。每个蜥蜴可以跳跃到与当前所在点曼哈顿距离小于等于d的地方。如果蜥蜴可以跳出这张地图说明他逃脱了。问你最后最少有几只蜥蜴无法跳出这个地图,也就是问最多能逃掉几只蜥蜴。

解题思路:首先我们先确定这个每个柱子上只能容纳一只蜥蜴对我们解题有没有影响,我们只要做到先让外边的蜥蜴跳跃,然后再让里面的蜥蜴跳跃那么就不会有冲突,所以这个限制是对我们解决问题没有影响的。然后就是建边跑最大流就行了。

我们将地图外模拟成汇点。因为对于每个柱子可以跳出的蜥蜴数量有限制,这就相当于限制了流量,所以我们需要对于
每个柱子点进行拆点,流量就为地图一的坚硬程度。addedge(i*m+j+1,n*m+i*m+j+1,q)
对于图二中有蜥蜴的点,我们让起点和这个点连一条流量为1的边。addedge(sp,i*m+j+1,1)
对于那些直接可以跳到地图外的点,我们就直接与终点建边,这样肯定是最优的选择。addedge(n*m+i*m+j+1,tp,inf)
然后其他的点就对于曼哈顿距离满足小于等于d的点建边就可以了。
除了起点向初始点的流量和限制的点的流量需要控制一下,其他都选择inf的流量就行了。

注意!他的输出是有几只蜥蜴跑不掉,0要输出no,还要考虑单复数和三单。我真是。。。。

完整代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=520;
const int inf=0x3f3f3f3f;
struct Edge{
    int u,v,c;
    int next;
}edge[maxn*maxn];
int n,m,d;
int edn;//边数
int head[maxn*maxn],dis[maxn*maxn];
int sp,tp;//原点,汇点

void addedge(int u,int v,int c)
{
    edge[edn].u=u; edge[edn].v=v; edge[edn].c=c;
    edge[edn].next=head[u]; head[u]=edn++;

    edge[edn].u=v; edge[edn].v=u; edge[edn].c=0;
    edge[edn].next=head[v]; head[v]=edn++;
}
int bfs()
{
    queue <int> q;
    memset(dis,-1,sizeof(dis));
    dis[sp]=0;
    q.push(sp);
    while(!q.empty())
    {
        int cur=q.front();
        q.pop();
        for(int i=head[cur];i!=-1;i=edge[i].next)
        {
            int u=edge[i].v;
            if(dis[u]==-1 && edge[i].c>0)
            {
                dis[u]=dis[cur]+1;
                q.push(u);
            }
        }
    }
    return dis[tp] != -1;
}
int dfs(int a,int b)
{
    int r=0;
    if(a==tp)return b;
    for(int i=head[a];i!=-1 && r<b;i=edge[i].next)
    {
        int u=edge[i].v;
        if(edge[i].c>0 && dis[u]==dis[a]+1)
        {
            int x=min(edge[i].c,b-r);
            x=dfs(u,x);
            r+=x;
            edge[i].c-=x;
            edge[i^1].c+=x;
        }
    }
    if(!r)dis[a]=-2;
    return r;
}

int dinic(int sp,int tp)
{
    int total=0,t;
    while(bfs())
    {
        while(t=dfs(sp,inf))
        total+=t;
    }
    return total;
}
char mp1[25][25];
char mp2[25][25];
int main()
{
    int T;
    scanf("%d",&T);
    int S=T;
    while(T--)
    {
        scanf("%d%d",&n,&d);
        edn=0;//初始化
        memset(head,-1,sizeof(head));
        // sp=1;tp=n;
        for(int i=0;i<n;i++)
        {
            scanf("%s",mp1[i]);
        }
        for(int i=0;i<n;i++)
        {
            scanf("%s",mp2[i]);
        }
        m=strlen(mp1[0]);
        sp=0,tp=2*n*m+1;
        int sum=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(mp2[i][j]=='L')
                {
                    addedge(sp,(i*m+j+1),1);
                    sum++;
                }
                if(mp1[i][j]!='0')
                    addedge((i*m+j+1),n*m+(i*m+j+1),mp1[i][j]-'0');
                if(i-d<0||i+d>=n||j-d<0||j+d>=m)
                    addedge(n*m+(i*m+j+1),tp,inf);
                else{
                    for(int i1=i-d;i1<=i+d;i1++)
                    {
                        for(int j1=j-d;j1<=j+d;j1++)
                        {
                            if(i1==i&&j1==j)
                                continue;
                            if(i1>=0&&i1<n&&j1>=0&&j1<m)
                            {
                                if(abs(i1-i)+abs(j1-j)<=d&&mp1[i1][j1]!='0')
                                    addedge(n*m+(i*m+j+1),i1*m+j1+1,inf);
                            }
                        }
                    }
                }
            }
        }
        int ans=dinic(sp,tp);
        ans=sum-ans;
        if(ans==0)
            printf("Case #%d: no lizard was left behind.\n",S-T);
        else if(ans==1)
            printf("Case #%d: 1 lizard was left behind.\n",S-T);
        else
            printf("Case #%d: %d lizards were left behind.\n",S-T,ans);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值