[bzoj]1066: [SCOI2007]蜥蜴

原题链接:蜥蜴


理解很重要,理解很重要,理解很重要!!
***

分析:

看到这题首先可能会想到搜索:裸图??
但是很明显搜索肯定会超时
观察题目,发现每根柱子有跳跃次数上限,想到了什么??
网络流!!
题目中有坑,每根柱子上只能站一只蜥蜴这个条件其实是没用的。
因为蜥蜴不动的话对柱子高度是没有影响的,只要按顺序跳跃就行了。
那么怎么考虑跳跃次数呢?
可以把每个柱子拆成两个点,一个入点一个出点,从入点到出点有单向流量,流量大小为柱子的高度。
从超级源向每一个蜥蜴的初始点的入点连流量为1的边。
每个能跳出去的点向超级汇连流量为无穷大的边。
再把所有柱子向能跳达的柱子连边,流量为无穷大。
这样子网络流模型就出来了,我们只需要从源点开始跑一遍最大流,然后拿蜥蜴的总个数减去最大流就是我们的答案了。
*
注意!**
第一次写的时候不知道写挂什么了,输出答案一直不对,调错调了一个半小时没有结果,然后重写一遍就对了。所以说如果发现查不出错的话一定要果断重构!!


下面是代码
#include <iostream>
#include <queue>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int inf=0x7fffffff;
int rr,cc,dd,g[25][25],d[5000],s=0,t=1000,mark[25][25];
int ver[500000],head[5000],next[500000],edge[500000],tot=1;
queue <int> q;
void add(int x,int y,int val){
    ver[++tot]=y;edge[tot]=val;next[tot]=head[x];head[x]=tot;
    ver[++tot]=x;edge[tot]=0;next[tot]=head[y];head[y]=tot;
}
bool judge(int x1,int y1,int x2,int y2){
    if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)>dd*dd)return false;
    else if(g[x1][y1]&&g[x2][y2])return true;
}
bool bfs();
int dinic(int x,int flow);
int main()
{
    //freopen("data.in","r",stdin);
    char ch[21];
    int num=0,ans=0,flow,maxflow=0;
    scanf("%d%d%d",&rr,&cc,&dd);
    for(int i=1;i<=rr;i++){
        scanf("%s",ch);
        for(int j=1;j<=cc;j++){
            g[i][j]=ch[j-1]-'0';
            mark[i][j]=++num;
            if(g[i][j])add(mark[i][j],mark[i][j]+400,g[i][j]);
        }
    }
    for(int i=1;i<=rr;i++){
        scanf("%s",ch);
        for(int j=1;j<=cc;j++){
            if(ch[j-1]=='L'){
                add(s,mark[i][j],1);
                ans++;
            }
        }
    }
    for(int i=1;i<=dd;i++){
        for(int j=1;j<=cc;j++){
            add(mark[i][j]+400,t,inf);
            add(mark[rr-i+1][j]+400,t,inf);
        }
    }
    for(int j=1;j<=dd;j++){
        for(int i=dd+1;i<=rr-dd;i++){
            add(mark[i][j]+400,t,inf);
            add(mark[i][cc-j+1]+400,t,inf);
        }
    }

    for(int i=1;i<=rr;i++)
        for(int j=1;j<=cc;j++)
            for(int p=(i-dd<=0)?1:i-dd;p<=min(rr,i+dd);p++)
                for(int q=(j-dd<=0)?1:j-dd;q<=min(cc,j+dd);q++)
                    if(judge(i,j,p,q)&&(i!=p||j!=q))
                        add(mark[i][j]+400,mark[p][q],inf);
    //cout<<1<<endl;
    while(bfs())
        while(flow=dinic(s,inf))maxflow+=flow;
    printf("%d\n",ans-maxflow);
    return 0;
}
bool bfs(){
    memset(d,0,sizeof(d));
    while(q.size())q.pop();
    q.push(s);d[s]=1;
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=next[i]){
            if(edge[i]&&!d[ver[i]]){
                q.push(ver[i]);
                d[ver[i]]=d[x]+1;
                if(ver[i]==t)return true;
            }
        }
    }
    return false;
}
int dinic(int x,int flow){
    if(x==t)return flow;
    int res=flow,k;
    for(int i=head[x];i&&res;i=next[i]){
        if(edge[i]&&d[ver[i]]==d[x]+1){
            k=dinic(ver[i],min(flow,edge[i]));
            if(!k)d[ver[i]]=0;
            edge[i]-=k;
            edge[i^1]+=k;
            res-=k;
        }
    }
    return flow-res;
}

猜你喜欢

转载自www.cnblogs.com/onglublog/p/9859683.html