BZOJ 1066 【SCOI2007】 蜥蜴

Description

  在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃
到边界外。 每行每列中相邻石柱的距离为$1$,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石
柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不
变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个
石柱上。

Input

  输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱
,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。

Output

  输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。

HINT

100%的数据满足:1<=r, c<=20, 1<=d<=4

 

  过了这么久,终于对简单的网络流的题有感觉了……虽然这道题的确很水

  这道题其实就是要求最多可以有多少条蜥蜴逃出去,再用蜥蜴总数减一下就可以了。于是把每根石柱拆成两个点,流量为石柱的高度;然后两个点之间暴力连边,跑一遍Dinic即可。边数较大,请自觉开大空间。

  这道题Discuss里有人在说距离是曼哈顿距离……不过$d<=4$好像和欧式距离也没有什么区别吧……汗……

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout);
#define maxn 1010
#define maxm 1000010
#define INF (1<<25)
 
using namespace std;
typedef long long llg;
 
int n,m,d,S,T,dep[maxn],de[maxn],ans;
int head[maxn],next[maxm],to[maxm],c[maxm],tt=1;
 
int getint(){
    int w=0;bool q=0;
    char c=getchar();
    while((c>'9'||c<'0')&&c!='-') c=getchar();
    if(c=='-') q=1,c=getchar();
    while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
    return q?-w:w;
}
 
int ji(int x){return x*x;}
void link(int x,int y,int z){
    to[++tt]=y;next[tt]=head[x];head[x]=tt;
    to[++tt]=x;next[tt]=head[y];head[y]=tt;
    c[tt-1]=z;
}
 
bool bfs(){
    for(int i=1;i<=T;i++) dep[i]=-1;
    int l=0,r=0; de[r++]=S; dep[S]=1;
    while(l!=r){
        int u=de[l++];
        for(int i=head[u],v;v=to[i],i;i=next[i])
            if(c[i] && dep[v]==-1)
                dep[v]=dep[u]+1,de[r++]=v;
    }
    return dep[T]!=-1;
}
  
int dfs(int u,int low){
    int res=0,now=0;
    if(u==T || !low) return low;
    for(int i=head[u],v;v=to[i],i;i=next[i])
        if(c[i] && dep[v]==dep[u]+1){
            res=dfs(v,min(low-now,c[i]));
            c[i]-=res; c[i^1]+=res; now+=res;
        }
    if(!now) dep[u]=-INF;
    return now;
}
 
int main(){
    n=getint(); m=getint(); d=getint();
    S=n*m*2+1; T=S+1;
    for(int i=1,now=1;i<=n;i++)
        for(int j=1;j<=m;j++,now++){
            char c=getchar();
            while(c>'9'||c<'0') c=getchar();
            if(c!='0'){
                link(now,now+n*m,c-'0');
                if(min(i,n-i+1)<=d) link(now+n*m,T,INF);
                if(min(j,m-j+1)<=d) link(now+n*m,T,INF);
                for(int x=1,nn=1;x<=n;x++)
                    for(int y=1;y<=m;y++,nn++)
                        if(ji(i-x)+ji(j-y)<=d*d)
                            if(i!=x || j!=y)
                                link(now+n*m,nn,INF);
            }
        }
    for(int i=1,now=1;i<=n;i++)
        for(int j=1;j<=m;j++,now++){
            char c=getchar();
            while(c!='.' && c!='L') c=getchar();
            if(c=='.') continue;
            link(S,now,1); ans++;
        }
    while(bfs()) ans-=dfs(S,INF);
    printf("%d",ans);
    return 0;
}
posted @ 2016-10-26 19:03  lcf2000  阅读(187)  评论(0编辑  收藏  举报