bzoj1066 蜥蜴

Description

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

Input

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

Output

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

Sample Input

5 8 2
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........

Sample Output

1

HINT

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

 

虽然它需要每个蜥蜴不能同时在同一石柱上,但是实际上我们可以让蜥蜴按一定顺序一个一个走,不同时走。那这些排列顺序里一定有一种方案是最优的。

为什么呢?因为最优解不可能出现蜥蜴A跳出去的路径中经过蜥蜴B的初始位置(标记为A->B),并且蜥蜴B跳出去的路径中经过蜥蜴A的初始位置(标记为B->A)。

也就是说要么蜥蜴A跳出去的路径中经过蜥蜴B的初始位置,那么蜥蜴B应该排在蜥蜴A前面走;要么蜥蜴B跳出去的路径中要经过蜥蜴A的初始位置,那么蜥蜴A应该排在蜥蜴B前走。

同样更不会出现A->B且B->C且C->A的情况、A->B且B->C且C->D且D->A的情况,等等。也就是说这个一定是有拓扑序的,不会有环。

那么我们在跑网络流的时候可以不用管它的顺序,直接跑最大流,只要是可行流就一定是可行解,因为一定会有一个蜥蜴的排列顺序满足这个可行流。每个石柱拆成两个点,这两个点间连一条最大流量为石柱高度的点,从S向每个蜥蜴所在石柱连一条最大流量为1的边。T与每个能跳出地图的石柱连一条最大流量为INF的边。石柱与石柱间若距离<=d也相互连最大流量为INF的边。

所以就拆点Dinic。

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=400*2+10,maxm=maxn*maxn,INF=0x3f3f3f3f;
int n,r,c,d,tot_col,tot_m,sz,S,T;
int bh[maxn][maxn];
char kk;
 
struct Col{
    int x,y,h;
}col[maxn];
 
int aa,ff;char cc;
int read() {
    aa=0;ff=1;cc=getchar();
    while(cc<'0'||cc>'9') {
        if(cc=='-') ff=-1;
        cc=getchar();
    }
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    return aa*ff;
}
 
struct Node{
    int x,y,flow,cap;
    Node(){}
    Node(int x,int y,int cap):x(x),y(y),cap(cap){flow=0;}
}node[2*maxm];
 
int cur[maxn],fir[maxn],nxt[2*maxm],e=1;
void add(int x,int y,int z) {
    node[++e]=Node(x,y,z); nxt[e]=fir[x];fir[x]=e;
    node[++e]=Node(y,x,0); nxt[e]=fir[y];fir[y]=e;
}
 
int dis[maxn],zz[maxn];
bool BFS() {
    int s=1,t=0,x,y,z;
    memset(dis,-1,sizeof(dis));
    dis[S]=0;zz[++t]=S;
    while(s<=t) {
        x=zz[s]; 
        for(y=fir[x];y;y=nxt[y]) {
            z=node[y].y;
            if(dis[z]!=-1||node[y].flow>=node[y].cap) continue;
            dis[z]=dis[x]+1;
            zz[++t]=z;
        }
        s++;
    }
    return dis[T]!=-1;
}
 
int DFS(int pos,int maxf) {
    if(pos==T||!maxf) return maxf;
    int now,z,rs=0;
    for(int &y=cur[pos];y;y=nxt[y]) {
        z=node[y].y;
        if(dis[z]!=dis[pos]+1||node[y].flow>=node[y].cap) continue;
        now=DFS(z,min(maxf,node[y].cap-node[y].flow));
        node[y].flow+=now; node[y^1].flow-=now;
        maxf-=now; rs+=now;
    }
    if(!rs) dis[pos]=-1;
    return rs;
}
 
int Dinic() {
    int rs=0;
    while(BFS()) {
        memcpy(cur,fir,sizeof(fir));
        rs+=DFS(S,INF);
    }
    return rs;
}
 
bool ok(int x,int y) {
    return sqrt((double)(col[x].x-col[y].x)*(col[x].x-col[y].x)+(double)(col[x].y-col[y].y)*(col[x].y-col[y].y))<=(double)d;
}
 
int main() {
    r=read();c=read();d=read(); int x;
    for(int i=1;i<=r;++i) {
        kk=getchar();
        while(kk<'0'||kk>'9') kk=getchar();
        x=kk-'0';
        for(int j=1;j<=c;++j) {
            if(x) {
                col[++tot_col].x=i;
                col[tot_col].y=j;
                col[tot_col].h=x;
                bh[i][j]=tot_col;
            }
            kk=getchar();x=kk-'0';
        }
    }
    S=2*tot_col+1;T=S+1;
    for(int i=1;i<=tot_col;++i) {
        add(i,i+tot_col,col[i].h);
        if(min(col[i].x,r-col[i].x+1)<=d||min(col[i].y,c-col[i].y+1)<=d) add(i+tot_col,T,INF);
        for(int j=1;j<=tot_col;++j){
            if(i==j) continue;
            else if(ok(i,j)) add(i+tot_col,j,INF);
        }
    }
    for(int i=1;i<=r;++i) {
        kk=getchar();
        while(kk!='.'&&kk!='L') kk=getchar();
        for(int j=1;j<=c;++j) {
            if(kk=='L') 
                add(S,bh[i][j],1),n++;
            kk=getchar();
        }
    }
    printf("%d",n-Dinic());
    return 0;
}

  

 

posted @ 2017-08-30 08:31  shixinyi  阅读(178)  评论(0编辑  收藏  举报