• HDU2732 Leapin' Lizards(最大流+拆点)


    题意:

    给两个n*m大小的图,第一个图上都是数字(0-3),每个数字代表一开时该坐标(i, j)上的柱子在第几次跳跃之后倒塌,0代表该位置上没有柱子,蜥蜴不能走没有柱子的地方;

    第二个图由两种符号'L'和'.'组成,'L'代表此处有一个lizard(蜥蜴),'.'代表没有蜥蜴。在同一时刻, 每个点上只能有一个蜥蜴给蜥蜴能跳的最大曼哈顿距离d,

    跳到矩阵的之外,(注意是整个矩阵的外边)即可以逃出去,当一只蜥蜴所处的位置能在跳跃范围d内跳出去的话就一定会跳出去。

    求最少有几只蜥蜴没跳出去。

    思路:

    拆点。每个点坐标表示为(i, j)第i行第j列,那么用i*m+j表示节点序号,那么把该节点拆成两个点,一个是跳入点i*m+j,一个是跳出点i*m+j+n*m,

    跳入点和跳出点不断交替连接,直到可以一步跳出边界时,让该点的跳出点与超级汇点t = n*m*2+1相连,边权为n*m,因为最多有m个蜥蜴走这个点;

    超级源点s = 0 与一开始是'L'的点相连,边权为1,因为一个点只有一只蜥蜴。

    然后跑最大流,判断一开始的蜥蜴数sum和最终maxflow的关系,对应输出即可。

    (注意下输出格式啊,was, were, lizard, lizards单复数)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 20 + 5;
    const int maxm = 1e5 + 5;
    const int inf = 0x3f3f3f3f;
    int n, m, d, T, s, t, maxflow;
    int head[maxn*maxn*2], tot, dis[maxn*maxn*2];
    char mp1[maxn][maxn], mp2[maxn][maxn];
    int num[maxn][maxn], sum;
    struct edge{
        int to, w, next;
    } ed[maxm];
    
    inline void add( int u, int v, int w ){
        ed[++tot].to = v; ed[tot].w = w; ed[tot].next = head[u]; head[u] = tot;
        ed[++tot].to = u; ed[tot].w = 0; ed[tot].next = head[v]; head[v] = tot;
    }
    
    inline int Abs( int a ){
        return a>=0 ? a:-a;
    }
    
    inline bool bfs(){
        memset( dis, 0, sizeof(dis) );
        queue<int> q;
        dis[s] = 1;
        q.push(s);
        while( !q.empty() ){
            int x = q.front();
            q.pop();
            for( int i=head[x]; i!=-1; i=ed[i].next ){
                int y = ed[i].to;
                if( ed[i].w && !dis[y] ){
                    dis[y] = dis[x] + 1;
                    q.push(y);
                    if( y==t ) return 1;
                }
            }
        }
        return 0;
    }
    
    inline int min( int a, int b ){
        return a<b ? a:b;
    }
    
    inline int dfs( int x, int flow ){
        if( x==t ) return flow;
        int res = flow, k;
        for( int i=head[x]; i!=-1 && res; i=ed[i].next ){
            int y = ed[i].to;
            if( ed[i].w && dis[y]==dis[x]+1 ){
                k = dfs( y, min(res, ed[i].w) );
                if( !k ) dis[y] = 0;
                ed[i].w -= k;
                ed[i^1].w += k;
                res -= k;
            }
        }
        return flow - res;
    }
    
    inline void dinic(){
        int flow = maxflow = 0;
        while( bfs() )
            while( flow=dfs(s, inf) ) maxflow += flow;
    }
    
    int main(){
        // freopen("in.txt", "r", stdin);
        scanf("%d", &T);
        for( int k=1; k<=T; k++ ){
            tot = 1; sum = 0;
            memset( head ,-1, sizeof(head) );
            scanf("%d %d", &n, &d);
            for( int i=1; i<=n; i++ )
                scanf("%s", mp1[i]+1);
            m = strlen(mp1[1]+1);
            s = 0, t = n*m*2+1;
            for( int i=1; i<=n; i++ ){
                scanf("%s", mp2[i]+1);
               for( int j=1; j<=m; j++ ){
                    num[i][j] = (i-1)*m+j;      //计算点(i, j)对应的序号
                    if( mp2[i][j]=='L' ){
                        add( s, num[i][j], 1 );     //一开始有蜥蜴的点,让s与他们连边
                        sum ++;
                    }
                }
            }
            for( int i=1; i<=n; i++ )
                for( int j=1; j<=m; j++ ){
                    if( mp1[i][j]=='0' ) continue;      //没有柱子,不处理
                    add( num[i][j], num[i][j]+n*m, mp1[i][j]-'0' );
                    if( n-i+1<=d || m-j+1<=d || j<=d || i<=d ) add( num[i][j]+n*m, t, n*m );    //该点可直接出去,与汇点连边
                    else{
                        for( int r=1; r<=n; r++ )
                            for( int c=1; c<=m; c++ ){
                                if( mp1[r][c]=='0' ) continue ; //没有柱子,不处理
                                if( r==i && c==j ) continue ;
                                if( Abs(r-i)+Abs(c-j)<=d ) add( num[i][j]+n*m, num[r][c], n*m ); //符合跳跃距离,跳出点与跳入点连边
                            }
                    }
                }
            dinic();
            printf("Case #%d: ", k);
            if( maxflow==sum ) puts("no lizard was left behind.");
            else if( sum-maxflow==1 ) puts("1 lizard was left behind.");
            else printf("%d lizards were left behind.
    ", sum-maxflow);
        }
    
        return 0;
    }
  • 相关阅读:
    day02【Collection、泛型】
    day11 【final、权限、内部类、引用类型】
    day10 【接口、多态】
    day09 【继承、super、this、抽象类】
    day08 【String类、static关键字、Arrays类、Math类】
    Java基本运算符
    Java非访问修饰符
    2020学习Java开发有前途吗?看看资深程序员怎么说
    两年Java后端开发,面试了几十家公司的面试分享
    五种方法创建java对象,你知道几种呢?
  • 原文地址:https://www.cnblogs.com/WAautomaton/p/10982774.html
Copyright © 2020-2023  润新知