BZOJ 1066

这题是网络流最大流。
难点在于拆点。因为石柱会不断缩水,所以将石柱拆成两个点,连一条流量为石柱高度的边。再将源点S与有蜥蜴的点连一条流量为1的边(每点只有一只蟋蟀),所有互相可以到达的点连∞的边,然后将可以跳到外面的点与汇点T连∞的边。跑最大流即可。


放一下代码,好渣的速度(>﹏<)

/**************************************************************
    Problem: 1066
    User: fantasticwtl
    Language: C++
    Result: Accepted
    Time:472 ms
    Memory:4744 kb
****************************************************************/

#include <cstdio>
#include <cmath>
#include <memory.h>
#include <algorithm>
using namespace std;
int a[21][21],d[1001],g[1001][1001],q[1001],n,m,cn,k,tot[21][21],ans,kk;
char c,enter;
void make(int x,int y)
{
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      if(sqrt((i-x)*(i-x)+(j-y)*(j-y))<=k&&(i!=x||j!=y))g[tot[x][y]+1][tot[i][j]]=10000000;//所有互相可以到达的点连∞的边
    if(x<=k||x>=n-k+1||y<=k||y>=m-k+1)g[tot[x][y]+1][cn]=10000000;//可以跳到外面的点与汇点T连∞的边
}
bool jz ()
{
    memset(d,0,sizeof(d));
    d[1]=1;q[1]=1;
    int h=0,t=1;
    while(h<t){
        h++;
        for(int i=1;i<=cn;i++)
         if(d[i]==0&&g[q[h]][i]){
             t++;d[i]=d[q[h]]+1;q[t]=i;
         }
        if(d[cn])return 1;
    }
    if(d[cn]==0)return 0;else return 1;
}
int find (int x,int y)
{
    if(x>=cn)return y;
    int a=0;
    for(int i=1;i<=cn;i++)
     if(d[i]==d[x]+1&&g[x][i]>0&&(a=find(i,min(y,g[x][i])))){g[x][i]-=a;g[i][x]+=a;return a;}
    return 0;
}
int main ()
{
        scanf("%d%d%d",&n,&m,&k);
        cn=1;
        for(int i=1;i<=n;i++){
          scanf("%c",&enter);
          for(int j=1;j<=m;j++){
             scanf("%c",&c);
             if(c>'0'){
                 a[i][j]=c-48;
                 cn++;
                 tot[i][j]=cn;
                 cn++;
             }
          }
        }
        cn++;
        for(int i=1;i<=n;i++){
          scanf("%c",&enter);
          for(int j=1;j<=m;j++){
             scanf("%c",&c);
             if(c=='L'){
                 ans=ans+1;
                 kk=tot[i][j];
                 g[1][kk]=1;
             }
             if(a[i][j]>0){
                 kk=tot[i][j];
                 g[kk][kk+1]=a[i][j];
                 make(i,j);
             }
          }
        }//输入部分
        int q=0,w=0;
        while(jz())if(w=(find(1,100000000)))q+=w;//Dinic
        ans=ans-q;
        printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值