• BZOJ_4439_[Swerc2015]Landscaping_最小割


    BZOJ_4439_[Swerc2015]Landscaping_最小割

    Description

    FJ有一块N*M的矩形田地,有两种地形高地(用‘#’表示)和低地(用‘.’表示)
    FJ需要对每一行田地从左到右完整开收割机走到头,再对每一列从上到下完整走到头,如下图所示
     
    对于一个4*4的田地,FJ需要走8次。
    收割机是要油的,每次从高地到低地或从低地到高地需要支付A的费用。
    但是FJ有黑科技,可以高地与低地的互变,都只需要一个支付B的费用。
    询问FJ需要支付最小费用。

    Input

    第一行包含四个整数N,M,A,B,意义如上文所述。
    接下来是一个N*M的字符串矩阵,表示农田的地形,’#’表示高地,’.’表示低地。

    Output

    只包含一个正整数,表示最小费用。
    1<=N,M<=50
    1<=A,B<=100000

    Sample Input

    5 4 1000 2000
    ...#
    #..#
    ...#
    ##..
    ###.

    Sample Output

    11000
    样例解释:
    把(2,1)的高地变成低地花费2000,燃料花费9000


     用最小割的思想。

    S->高地(B) 低地->T(B),割这些边表示一开始将高低互换。

    然后对于每个点向四周连边(A),割这个表示支付A从而改变与四周的联系,可以理解为边是双向的。

    求最小割即可。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 3050
    #define M 300050
    #define S (n*m+1)
    #define T (n*m+2)
    #define inf 100000000
    #define p(i,j) ((i-1)*m+j)
    int head[N],to[M],nxt[M],flow[M],cnt=1,n,m,dep[N],Q[N],l,r;
    inline void add(int u,int v,int f) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f;
        to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0;
    }
    bool bfs() {
        memset(dep,0,sizeof(dep));
        dep[S]=1; l=r=0; Q[r++]=S;
        while(l<r) {
            int x=Q[l++],i;
            for(i=head[x];i;i=nxt[i]) {
                if(!dep[to[i]]&&flow[i]) {
                    dep[to[i]]=dep[x]+1;
                    if(to[i]==T) return 1;
                    Q[r++]=to[i];
                }
            }
        }
        return 0;
    }
    int dfs(int x,int mf) {
        if(x==T) return mf;
        int nf=0,i;
        for(i=head[x];i;i=nxt[i]) {
            if(dep[to[i]]==dep[x]+1&&flow[i]) {
                int tmp=dfs(to[i],min(mf-nf,flow[i]));
                if(!tmp) dep[to[i]]=0;
                nf+=tmp;
                flow[i]-=tmp;
                flow[i^1]+=tmp;
                if(nf==mf) break;
            }
        }
        return nf;
    }
    void dinic() {
        int ans=0,f;
        while(bfs()) while(f=dfs(S,inf)) ans+=f;
        printf("%d
    ",ans);
    }
    char s[60];
    int main() {
        int A,B,i,j;
        scanf("%d%d%d%d",&n,&m,&A,&B);
        for(i=1;i<=n;i++) {
            scanf("%s",s+1);
            for(j=1;j<=m;j++) {
                if(s[j]=='#') {
                    add(S,p(i,j),B);
                }else {
                    add(p(i,j),T,B);
                }
            }
        }
        for(i=1;i<=n;i++) {
            for(j=1;j<=m;j++) {
                if(i>1) add(p(i,j),p(i-1,j),A);
                if(i<n) add(p(i,j),p(i+1,j),A);
                if(j>1) add(p(i,j),p(i,j-1),A);
                if(j<m) add(p(i,j),p(i,j+1),A);
            }
        }
        dinic();
    }
    
  • 相关阅读:
    终于搞明白Unicode,ASCII,UTF8,UCS2编码是啥了
    在IDEA中构建Tomcat项目流程
    在执行jar包时如何使用调优参数
    在浏览器运行JS脚本实现博客园文章批量删除
    线索二叉树之初步剖析(献给那些想形象思考二叉树遍历过程的人)
    二分查找c++实现
    c++学习之初话 函数指针和函数对象 的因缘
    继承与动态内存分配
    C++入门之初话多态与虚函数
    c++入门之类继承初步
  • 原文地址:https://www.cnblogs.com/suika/p/8967367.html
Copyright © 2020-2023  润新知