• 题解 P2472 【[SCOI2007]蜥蜴】


    P2472 [SCOI2007]蜥蜴

    题目背景
    07四川省选

    题目描述
    在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。

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

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

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


    解决这题的关键是理解这句话:石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为1,则蜥蜴离开后消失

    我们把这句话转换一下,每个石柱 (i) 可以用石柱高度 (hi)。这是一个限制条件:使用次数,所以我们想到了最大流。

    不能逃脱的蜥蜴数即为总蜥蜴数 - 逃脱的蜥蜴数,所以我们现在思考怎么建图

    建模

    最大流的核心在于限制

    由限制条件,对网络流模型极其敏感我们可知道:石柱一定是要拆成两个点的,两点之间边容量为石柱高度 (h) ,这样可以限制一个石柱只能跳 (h)

    由最大流答案不可能大于蜥蜴总数,所以我们可以联想到由汇点向蜥蜴所在的石柱连边,容量为 1

    由石柱之间在规定距离内可以相互到达,傻子都会我们可以在距离内的石柱连一条容量为INF的边

    由要跳出去可得:在跳到外围距离小于d的石柱连一条容量为INF的边

    注意:因为每次都要消耗石柱高度,所以连入石柱的边连 石柱1 ,连出石柱的边从 石柱2 出发,从而达到路过石柱消耗高度这一限制

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int RD(){
        int out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const int maxn = 100019,INF = 1e9;
    int num,nume = 1,tot;
    int lenx,leny,d;
    int map[190][190];
    int L[190][190];
    int s,t,maxflow;
    int head[maxn];
    struct Node{
        int v,dis,nxt;
        }E[maxn << 2];
    void add(int u,int v,int dis){
        E[++nume].nxt = head[u];
        E[nume].v = v;
        E[nume].dis = dis;
        head[u] = nume;
        }
    int lev[maxn];
    bool bfs(){
        queue<int>Q;
        memset(lev,0,sizeof(lev));
        Q.push(s);
        lev[s] = 1;
        while(!Q.empty()){
            int u = Q.front();
            Q.pop();
            for(int i = head[u];i;i = E[i].nxt){
                int v = E[i].v;
                if(E[i].dis && !lev[v]){
                    lev[v] = lev[u] + 1;
                    Q.push(v);
                    if(v == t)return 1;
                    }
                }
            }
        return 0;
        }
    int Dinic(int u,int flow){
        if(u == t)return flow;
        int rest = flow,k;
        for(int i = head[u];i;i = E[i].nxt){
            int v = E[i].v;
            if(E[i].dis && lev[v] == lev[u] + 1 && rest){
                k = Dinic(v,min(rest,E[i].dis));
                if(!k)lev[v] = 0;
                E[i].dis -= k;
                E[i ^ 1].dis += k;
                rest -= k;
                }
            
            }
        return flow - rest;
        }
    double getdis(int x1,int y1,int x2,int y2){
        return ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
        }
    int getindex(int x,int y){
        return (x - 1) * leny + y;
        }
    int main(){
        lenx = RD();leny = RD();d = RD();
        char temp;
        for(int i = 1;i <= lenx;i++){
            for(int j = 1;j <= leny;j++){
                cin>>temp;
                map[i][j] = temp - '0';
                }
            }
        for(int i = 1;i <= lenx;i++){
            for(int j = 1;j <= leny;j++){
                cin>>temp;
                if(temp == 'L'){
                    L[i][j] = 1;
                    num++;
                    }
                }
            }
        //石头1部从1到tot(lenx * leny),2部 + tot,石头编号为(i - 1) * leny + j
        tot = lenx * leny;
        s = tot * 2 + 1,t = s + 1;
        for(int i = 1;i <= lenx;i++){
            for(int j = 1;j <= leny;j++){
                int I = getindex(i,j);
                if(map[i][j]){
                    add(I,I + tot,map[i][j]);
                    add(I + tot,I,0);
                    if(i + d > lenx || i - d < 1 || j + d > leny || j - d < 1){
                        add(I + tot,t,INF);
                        add(t,I + tot,INF);
                        }
                    if(L[i][j]){
                        add(s,I,1);
                        add(I,s,0);
                        }
                    }
                }
            }
        for(int x1 = 1;x1 <= lenx;x1++){
            for(int y1 = 1;y1 <= leny;y1++){
                for(int x2 = 1;x2 <= lenx;x2++){
                    for(int y2 = 1;y2 <= leny;y2++){
                        if(getdis(x1,y1,x2,y2) <= d * d){
                            int u = getindex(x1,y1),v = getindex(x2,y2);
                            add(u + tot,v,INF);
                            add(v,u + tot,0);
                            add(v + tot,u,INF);
                            add(u,v + tot,0);
                            }
                        }
                    }
                }
            }
        int flow = 0;
        while(bfs())while(flow = Dinic(s,INF))maxflow += flow;
        printf("%d
    ",num - maxflow);
        return 0;
        }
    
  • 相关阅读:
    前端提示“页面正在载入”的功能实现
    JSON那些事
    如何让nodejs同步操作
    nodejs的一些局限
    《javascript高级程序设计》读书笔记——作用域
    svn教程
    从雷军谈小米中的一些思考
    云Vps安全设置
    不同服务器数据库之间的数据操作
    C#语言的Excel文件导入导出
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9285519.html
Copyright © 2020-2023  润新知