【BZOJ】1066: [SCOI2007]蜥蜴

【算法】网络流-最大流(dinic)

【题解】

构图思路:

因为石柱高度是可以被消耗的,即一根石柱可通过的蜥蜴数量有限,取舍问题中这样表示容量的属性显然可以作为网络流中的边

于是将一根石柱拆成顶部和底部,中间连一条容量为石柱高度的边。

超级源向有蜥蜴的石柱顶连一条容量为1的边(表示一只蜥蜴)。

可以跳出地图的石柱底向超级汇连一条容量为inf的边。

d距离内的两根石柱连一条容量为inf的边。

记得结果要的是逃不掉的蜥蜴数。

edge数组开大!!!

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1000,inf=0x3f3f3f3f;
struct edge{int from,v,flow;}e[500000];
int n,m,d,first[maxn],cur[maxn],q[510],p[30][30],dt[maxn],S=0,T=801,tot=1,ans=0;
void insert(int u,int v,int w)
{tot++;e[tot].v=v;e[tot].flow=w;e[tot].from=first[u];first[u]=tot;
 tot++;e[tot].v=u;e[tot].flow=0;e[tot].from=first[v];first[v]=tot;}
bool bfs()
{
    memset(dt,-1,sizeof(dt));
    int head=0,tail=1;q[0]=S;dt[S]=0;
    while(head!=tail)
     {
         int x=q[head++];if(head>=501)head=0;
         for(int i=first[x];i;i=e[i].from)
          if(dt[e[i].v]==-1&&e[i].flow>0)
           {
               q[tail++]=e[i].v;if(tail>=501)tail=0;
               dt[e[i].v]=dt[x]+1;
           }
     }
    if(dt[T]==-1)return 0;
    return 1;
}
int dinic(int x,int a)
{
    if(x==T||a==0)return a;
    int flow=0,f;
    for(int& i=cur[x];i;i=e[i].from)
     if(dt[e[i].v]==dt[x]+1&&(f=dinic(e[i].v,min(a,e[i].flow)))>0)
      {
          e[i].flow-=f;
          e[i^1].flow+=f;//tot从2开始!建反向弧! 
          flow+=f;
          a-=f;
          if(a==0)break;
      }
    return flow;
}
int main()
{
    scanf("%d%d%d",&n,&m,&d);
    int cnt=0;
    char s[30];
    for(int i=1;i<=n;i++)
     {
         scanf("%s",s+1);
         for(int j=1;j<=m;j++)
          {
              cnt++;int u;
              p[i][j]=cnt;
              u=s[j]-'0';
              if(u)insert(cnt,cnt+400,u);
          }
     }
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      for(int x=max(i-d,1);x<=min(i+d,n);x++)
       for(int y=max(j-d,1);y<=min(j+d,m);y++)
        if((i!=x||j!=y)&&(i-x)*(i-x)+(j-y)*(j-y)<=(d*d))
         insert(p[i][j]+400,p[x][y],inf);
    for(int i=1;i<=n;i++)
     {
         scanf("%s",s+1);
         for(int j=1;j<=m;j++)
          if(s[j]=='L')insert(S,p[i][j],1),ans++;
     }
    for(int i=d+1;i<=n-d;i++)
     for(int j=1;j<=d;j++)
      {
          insert(p[i][j]+400,T,inf);
          insert(p[i][m-j+1]+400,T,inf);
      }
    for(int i=1;i<=d;i++)
     for(int j=1;j<=m;j++)
      {
          insert(p[i][j]+400,T,inf);
          insert(p[n-i+1][j]+400,T,inf);
      }
    while(bfs())
     {
         for(int i=0;i<=801;i++)cur[i]=first[i];
         ans-=dinic(S,inf);
     }
    printf("%d",ans);
    return 0;
}
View Code

 

posted @ 2017-02-22 22:01  ONION_CYC  阅读(350)  评论(0编辑  收藏  举报