• UVA


    题目链接

    You are working for the International Company for Pool Construction, a construction company which specializes in building swimming pools. A new client wants to build several new pool areas.

    A pool area is a rectangular grid of w × h square patches, consisting of zero or more (possibly disconnected) pools. A pool consists of one or multiple connected hole patches, which will later be filled with water. In the beginning, you start with a piece of land where each patch is either a hole in the ground (’.’) or flat grass (’#’). In order to transform this land into a pool area, you must adhere to the following:

    • You can leave a patch as it is. This costs nothing.

    • If the patch is grass in the beginning, you can dig a hole there. This costs d EUR.

    • If the patch is a hole in the beginning, you can fill the hole and put grass on top. This costs f EUR.

    • You must place special boundary elements along each edge running between a final grass patch and a final hole patch, to ensure that water does not leak from the pool. This costs b EUR per boundary element.

    • The outermost rows and columns of the pool area must always be grass.
      You are given the task of calculating the cost of the cheapest possible pool area given the layout of

      the existing piece of land.

      Input

      On the first line a positive integer: the number of test cases, at most 100. After that per test case:

      • one line with two integers w and h (2 ≤ w, h ≤ 50): the width and height of the building site.

      • one line with three integers d, f and b (1 ≤ d,f,b ≤ 10000): the costs for digging a new hole, filling an existing hole, and building a boundary element between a pool and grass patch.

      • h lines of w characters each, denoting the layout of the original building site. Output

        Per test case:

        • one line with an integer: the cost of building the cheapest possible pool area from the original piece of land.

        Sample Input

        3
        33 551 #.#
        #.#
        ###
        54 181 #..## ##.## #.#.# ##### 22
        27 11 11 #.
        .#

        Sample Output

        9 27 

    题意:给一个h*w的矩阵,每个格子中是‘#‘和‘.‘两个符号之一,分别代表草和洞。你可以将洞变成草,花费f,也可以把草变成洞,花费为d,最后还要在草和洞之间修围栏,每条边花费为b,而且整个矩阵第一行/列和最后一行/列必须是草,求最小花费。

    ​ 题解:这题和poj 3469其实是类似的,首先处理矩形四周,强制变成草丛,对于非四周,如果s代表草丛,t代表洞,那么可以用一个点代表每个格子p,s向p连边,容量为该格子变成洞的费用,p向t连边,容量为f,只不过有的每个格子已经初始指定了是草还是洞,所以有一条边的容量为0,可以不用连。对于四周必须是草,那么可以s向p连inf的边保证这条边不会被割去。对于修围栏,其实就是“相邻两个格子属于不同集合”的意思,所以我们对相邻的两个格子u和v,连u->v和v->u的边,容量为b。然后就跑最小割就行了。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<stack>
    using namespace std;
    #define rep(i,a,n) for (int i=a;i<n;i++)
    #define per(i,a,n) for (int i=n-1;i>=a;i--)
    #define pb push_back
    #define fi first
    #define se second
    typedef vector<int> VI;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int inf=0x3fffffff;
    const ll mod=1000000007;
    char s[55][55];
    
    const int maxn=3000;//点数的最大值
    const int maxm=205000;//边数的最大值
    struct Node
    {
        int from,to,next;
        int cap;
    }edge[maxm];
    int tol;
    int dep[maxn];//dep为点的层次
    int head[maxn];
    void init()
    {
        tol=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v,int w)//第一条边下标必须为偶数
    {
        edge[tol].from=u;
        edge[tol].to=v;
        edge[tol].cap=w;
        edge[tol].next=head[u];
        head[u]=tol++;
        edge[tol].from=v;
        edge[tol].to=u;
        edge[tol].cap=0;
        edge[tol].next=head[v];
        head[v]=tol++;
    }
    int BFS(int start,int end)
    {
        int que[maxn];
        int front,rear;
        front=rear=0;
        memset(dep,-1,sizeof(dep));
        que[rear++]=start;
        dep[start]=0;
        while(front!=rear)
        {
            int u=que[front++];
            if(front==maxn)front=0;
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].to;
                if(edge[i].cap>0&&dep[v]==-1)
                {
                    dep[v]=dep[u]+1;
                    que[rear++]=v;
                    if(rear>=maxn)rear=0;
                    if(v==end)return 1;
                }
            }
        }
        return 0;
    }
    int dinic(int start,int end)
    {
        int res=0;
        int top;
        int stack[maxn];//stack为栈,存储当前增广路
        int cur[maxn];//存储当前点的后继
        while(BFS(start,end))
        {
            memcpy(cur,head,sizeof(head));
            int u=start;
            top=0;
            while(1)
            {
                if(u==end)
                {
                    int min=inf;
                    int loc;
                    for(int i=0;i<top;i++)
                        if(min>edge[stack[i]].cap)
                        {
                            min=edge[stack[i]].cap;
                            loc=i;
                        }
                    for(int i=0;i<top;i++)
                    {
                        edge[stack[i]].cap-=min;
                        edge[stack[i]^1].cap+=min;
                    }
                    res+=min;
                    top=loc;
                    u=edge[stack[top]].from;
                }
                for(int i=cur[u];i!=-1;cur[u]=i=edge[i].next)
                    if(edge[i].cap!=0&&dep[u]+1==dep[edge[i].to])
                        break;
                if(cur[u]!=-1)
                {
                    stack[top++]=cur[u];
                    u=edge[cur[u]].to;
                }
                else
                {
                    if(top==0)break;
                    dep[u]=-1;
                    u=edge[stack[--top]].from;
                }
            }
        }
        return res;
    }
    int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
    int main()
    {
        int cas;
        scanf("%d",&cas);
        while(cas--)
        {
            init();
            int w,h,d,f,b;
            scanf("%d%d%d%d%d",&w,&h,&d,&f,&b);  //h*w
            ll ans=0;
            rep(i,1,h+1) scanf("%s",s[i]+1);
            rep(j,1,w+1)
            {
                if(s[1][j]=='.') ans+=1ll*f,s[1][j]='#';
                if(s[h][j]=='.') ans+=1ll*f,s[h][j]='#';
            }
            rep(i,1,h+1)
            {
                if(s[i][1]=='.') ans+=1ll*f,s[i][1]='#';
                if(s[i][w]=='.') ans+=1ll*f,s[i][w]='#';
            }
            int st=0,ed=w*h+1;
            rep(i,1,h+1) rep(j,1,w+1)
            {
                if(i==1||j==1||i==h||j==w)
                    addedge(st,w*(i-1)+j,inf);
                else
                {
                    if(s[i][j]=='.')
                        addedge((i-1)*w+j,ed,f);
                    else if(s[i][j]=='#')
                        addedge(st,(i-1)*w+j,d);
                }
                rep(k,0,4)
                {
                    int x=i+dx[k],y=j+dy[k];
                    if(x<1||x>h||y<1||y>w) continue;
                    addedge(w*(x-1)+y,w*(i-1)+j,b);
                }
            }
            ans+=1ll*dinic(st,ed);
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    《梦段代码》阅读笔记03
    用户场景
    冲刺!
    冲刺!
    周总结8
    冲刺!
    冲刺!
    PMS权限管理和鉴权过程
    PMS构造函数以及apk如何扫描
    PMS的学习之旅
  • 原文地址:https://www.cnblogs.com/tarjan/p/7275772.html
Copyright © 2020-2023  润新知