hdu2732,网络流

果然建图是关键。

拆点,拆出来两点之间连边,可增广量为柱子能承受的负荷,互相能跳的到的柱子,及距离在d以内的,从node2到node1连INF的边,源点到有lizards的位置连一条1的边,每个能跳出的柱子与汇点连一条INF的边。

这题输出有点坑,no和1的时候用was,其他的用were,汗!!!后来看到别人的题解才知道。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define INF 200000000
char s[25][25];
int n,m,d,map[505][505],first[1005],next[200005],flow[1005][1005],queue[100005],idx,lever[1005];
struct edge
{
    int u;
    int v;
    int f;
}en[200005];
int min(int a,int b)
{
    return a>b?b:a;
}
void add(int s,int t,int f)
{
    idx++;
    en[idx].u=s;
    en[idx].v=t;
    en[idx].f=f;
    next[idx]=first[s];
    first[s]=idx;
}
int bfs(int s)
{
    int begin,end,x,i,j,k,l;
    memset(lever,0,sizeof(lever));
    lever[s]=1;
    queue[0]=s;
    begin=0;end=1;
    while(begin!=end)
    {
        x=queue[begin];
        begin++;
        for(i=first[x];i!=-1;i=next[i])
        {
            if(lever[en[i].v]==0&&en[i].f>flow[x][en[i].v])
            {
                lever[en[i].v]=lever[x]+1;
                queue[end]=en[i].v;
                end++;
                if(en[i].v==2*n*m+1)
                    return 1;
            }
        }
    }
    if(lever[2*n*m+1]==0)
        return 0;
    else
        return 1;
}
int dfs(int s,int kuo)
{
    int i,j,k,l,tmp,so;
    if(s==2*n*m+1)
        return kuo;
    so=0;
    for(i=first[s];i!=-1;i=next[i])
    {
        if(lever[en[i].v]==lever[s]+1&&en[i].f>flow[s][en[i].v])
        {
            tmp=dfs(en[i].v,min(en[i].f-flow[s][en[i].v],kuo));
            if(tmp==0)
                lever[en[i].v]=-1;
            so+=tmp;
            kuo-=tmp;
            flow[s][en[i].v]+=tmp;
            flow[en[i].v][s]-=tmp;
            if(kuo==0)
                break;
        }
    }
    return so;
}
int main()
{
    int i,j,k,l,t,mf,sum,count,qqq;
    while(scanf("%d",&t)!=EOF)
    {
        count=0;
        while(t--)
        {
            memset(first,-1,sizeof(first));
            memset(next,-1,sizeof(next));
            memset(flow,0,sizeof(flow));
            scanf("%d%d",&n,&d);
            idx=0;
            for(i=0;i<n;i++)
                scanf("%s",s[i]);
            memset(map,0,sizeof(map));
            m=strlen(s[0]);
            for(i=0;i<n;i++)
                for(j=0;j<m;j++)
                for(k=0;k<n;k++)
                for(l=0;l<m;l++)
                if(s[i][j]>'0'&&s[k][l]>'0'&&abs(i-k)+abs(j-l)<=d)
                map[i*m+j+1][k*m+l+1]=1;
            for(i=1;i<=n*m;i++)
                for(j=1;j<=n*m;j++)
            {
                if(map[i][j]==1)
                {
                    add(i+n*m,j,INF);
                    add(j,i+n*m,0);
                }
            }
            for(i=0;i<n;i++)
                for(j=0;j<m;j++)
            {
                if(s[i][j]>'0')
                {
                    add(i*m+j+1,i*m+j+1+n*m,s[i][j]-'0');
                    add(i*m+j+1+n*m,i*m+j+1,0);
                    if(min(i+1,min(n-i,min(j+1,m-j)))<=d)
                    {
                        add(i*m+j+1+n*m,2*n*m+1,INF);
                        add(2*n*m+1,i*m+j+1+n*m,0);
                    }
                }
            }
            for(i=0;i<n;i++)
                scanf("%s",s[i]);
            sum=0;
            for(i=0;i<n;i++)
            {
                for(j=0;j<m;j++)
                {
                    if(s[i][j]=='L')
                    {
                        sum++;
                        add(0,i*m+j+1,1);
                        add(i*m+j+1,0,0);
                    }
                }
            }
            mf=0;
            while(bfs(0))
            {
                mf+=dfs(0,INF);
            }
            if(mf==sum)
                printf("Case #%d: no lizard was left behind.\n",++count);
            else if(sum-mf!=1)
                printf("Case #%d: %d lizards were left behind.\n",++count,sum-mf);
            else
                printf("Case #%d: 1 lizard was left behind.\n",++count);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值