bzoj1066

网络流:

若该点能跳出边界,即与t连接一条指向t的容量为a[i][j]-‘0’的边,

若该点起始有蜥蜴,就与s连接一条指向该点的虚点的容量为a[i][j]的边(为什么是虚点后面讲)

若其中任意两点,x,y有石柱且可达:1.x,y之间连一条x指向y的虚点的容量为min(v[x],v[y])的边

                                                                 2.x,y之间连一条y指向x的虚点的容量为min(v[x],v[y])的边

若该点有虚点,从虚点连一条指向实点的容量为v的边

在这张图上跑网络流,最大流就是可以跳出去的蜥蜴数

所以ans=sum-maxflow

为什么是虚点呢,因为若直接连向该点,则忽略了该点最多不能超过v个蜥蜴跳的限制,所以建立虚点,从虚点向实点连一条v容量的边就能保证这个条件

/**************************************************************

    Problem: 1066

    User: syh0313

    Language: C++

    Result: Accepted

    Time:60 ms

    Memory:13020 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <string>

using namespace std;

const int inf=10000100;

const int maxe=500010;

const int maxd=1010;

const int xu=500;

int n,m,d,s,t,topt,nt[maxe],st[maxe],to[maxe],cap[maxe];

int inc[maxd],pre[maxd],q[1000010],head,tail,ans,sum;

bool f[maxd],v[30][30];

char a[30][30],c;

int biao(int x,int y) {return (x-1)*m+y;}

void add(int x,int y,int v)

{

    to[topt]=y; nt[topt]=st[x]; st[x]=topt; cap[topt]=v; topt++;

    to[topt]=x; nt[topt]=st[y]; st[y]=topt; cap[topt]=0; topt++;

}

bool bfs()

{

    for (int i=1;i<=t;i++) pre[i]=-1,f[i]=1,inc[i]=0;

    inc[s]=inf; q[1]=s; head=tail=1;

    while (head<=tail)

    {

        int x=q[head++]; int p=st[x];

        while (p!=-1)

        {

            if (!inc[to[p]] && cap[p])

            {

                inc[to[p]]=min(inc[x],cap[p]);

                pre[to[p]]=p;

                q[++tail]=to[p];

            }

            p=nt[p];

        }

    }

    if (inc[t]==0) return 0;

return 1;

}

int main()

{

    //freopen("1.in","r",stdin);

    //freopen("my.out","w",stdout);

    s=1001; t=1002; memset(st,-1,sizeof st);

    scanf("%d%d%d%c",&n,&m,&d,&c);

    for (int i=1;i<=n;i++)

    {

     for (int j=1;j<=m;j++)

      {a[i][j]=getchar(); add(biao(i,j),biao(i,j)+xu,a[i][j]-'0');}

     c=getchar();

    }

    for (int i=1;i<=n;i++)

     for (int j=1;j<=m+1;j++)

     {

        c=getchar();

        if (c=='L') {add(s,biao(i,j),1); sum++;}

     }

    for (int i=1;i<=n;i++)

     for (int j=1;j<=m;j++)

     {

        if ((i<=d || n-i+1<=d || j<=d || m-j+1<=d)&& a[i][j]>='1' && a[i][j]<='4')

          add(biao(i,j)+xu,t,inf);

        if (a[i][j]>='1' && a[i][j]<='4')

        for (int k=1;k<=n;k++)

         for (int l=1;l<=m;l++)

          if ((i-k)*(i-k)+(j-l)*(j-l)<=d*d && a[k][l]>='1' && a[k][l]<='4')

          {

            if (k==i && l==j) continue;

            add(biao(i,j)+xu,biao(k,l),inf);

            v[i][j]=1; v[k][l]=1;

          }

     }

    while (bfs())

    {

        ans+=inc[t];

        int se=pre[t];

        while (se!=-1)

        {

            cap[se]-=inc[t];

            cap[se^1]+=inc[t];

            se=pre[to[se^1]];

        }

    }

    printf("%d\n",sum-ans);

return 0;

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值