• UVA-1515 Pool construction (最小割)


    题目大意:有一块地,分成nxm块。有的块上长着草,有的块上是荒地。将任何一块长着草的块上的草拔掉都需要花费d个力气,往任何一块荒地上种上草都需要花费f个力气,在草和荒地之间架一个篱笆需要花费b个力气,如果一块草地四周都是荒地,则得花掉4b个力气。现在,要求最外一圈都种上草,草地与荒地之间要用篱笆隔开,最少需要花费多少个力气?

    题目分析:有篱笆要把草地和荒地隔开意味着把所有的块分成两个“阵营”。增加源点和汇点,用源点s代表草地“阵营”头领,汇点t代表荒地“阵营”头领,在初始时,从s向所有的草地(在边界处的除外)连一条弧,容量为d,表示该块草地要背叛头领s投奔敌人的代价;从所有的荒地向汇点连一条弧,容量为f,表示该块荒地放弃头领t的代价;对于任意一个块u,向所有与它相邻的v连一条弧,容量为b,表示u与v对立的代价。我们要做的就是用最少的代价这些块分成两个“阵营”,实际上就是求最小割。

    CP:第一次用ISAP来写网络流。。。

    代码如下:

    # include<iostream>
    # include<cstdio>
    # include<vector>
    # include<queue>
    # include<cstring>
    # include<iostream>
    using namespace std;
    
    const int INF=1<<30;
    const int maxn=2505;
    
    int n,m;
    char p[60][60];
    
    struct Edge
    {
        int fr,to,cap,fw;
        Edge(int fr,int to,int cap,int fw){
            this->fr=fr;
            this->to=to;
            this->cap=cap;
            this->fw=fw;
        }
    };
    struct ISAP
    {
        vector<Edge>edges;
        vector<int>G[maxn];
        int d[maxn],gap[maxn],p[maxn];
        int n,s,t,vis[maxn],cur[maxn];
    
        void init(int n)
        {
            this->n=n;
            edges.clear();
            for(int i=0;i<n;++i) G[i].clear();
        }
    
        void addEdge(int u,int v,int cap)
        {
            edges.push_back(Edge(u,v,cap,0));
            edges.push_back(Edge(v,u,0,0));
            int m=edges.size();
            G[u].push_back(m-2);
            G[v].push_back(m-1);
        }
    
        void bfs(int u)
        {
            memset(vis,0,sizeof(vis));
            d[u]=0;
            queue<int>q;
            q.push(u);
            vis[u]=1;
            while(!q.empty())
            {
                int x=q.front();
                q.pop();
                for(int i=0;i<G[x].size();++i){
                    Edge &e=edges[G[x][i]];
                    if(e.cap>0) continue;
                    int v=edges[G[x][i]^1].fr;
                    if(!vis[v]){
                        vis[v]=1;
                        d[v]=d[x]+1;
                        q.push(v);
                    }
                }
            }
        }
    
        int augment()
        {
            int a=INF;
            for(int u=t;u!=s;u=edges[p[u]].fr){
                Edge &e=edges[p[u]];
                a=min(a,e.cap-e.fw);
            }
            for(int u=t;u!=s;u=edges[p[u]].fr){
                edges[p[u]].fw+=a;
                edges[p[u]^1].fw-=a;
            }
            return a;
        }
    
        int maxFlow(int s,int t)
        {
            this->s=s,this->t=t;
            bfs(t);
            int flow=0;
            memset(gap,0,sizeof(gap));
            for(int i=0;i<n;++i) ++gap[d[i]];
            memset(cur,0,sizeof(cur));
            int x=s;
            while(d[s]<n)
            {
                if(x==t){
                    flow+=augment();
                    x=s;
                }
                int flag=false;
                for(int i=cur[x];i<G[x].size();++i){
                    Edge &e=edges[G[x][i]];
                    if(e.cap>e.fw&&d[x]==d[e.to]+1){
                        flag=true;
                        p[e.to]=G[x][i];
                        cur[x]=i;
                        x=e.to;
                        break;
                    }
                }
                if(!flag){
                    int m=n-1;
                    for(int i=0;i<G[x].size();++i){
                        Edge &e=edges[G[x][i]];
                        if(e.cap>e.fw) m=min(m,d[e.to]);
                    }
                    if((--gap[d[x]])==0) break;
                    d[x]=m+1;
                    ++gap[d[x]];
                    cur[x]=0;
                    if(x!=s) x=edges[p[x]].fr;
                }
            }
            return flow;
        }
    };
    ISAP solver;
    
    int d,f,b;
    int dd[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
    
    bool ok(int x,int y)
    {
        return x>=1&&x<=n&&y>=1&&y<=m;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int cnt=0;
            scanf("%d%d",&m,&n);
            scanf("%d%d%d",&d,&f,&b);
            for(int i=1;i<=n;++i){
                scanf("%s",p[i]+1);
                if(p[i][1]=='.'){
                    ++cnt;
                    p[i][1]='#';
                }
                if(m>1&&p[i][m]=='.'){
                    ++cnt;
                    p[i][m]='#';
                }
                if(i==1||i==n)
                    for(int j=1;j<=m;++j)
                        if(p[i][j]=='.'){
                            ++cnt;
                            p[i][j]='#';
                        }
            }
            solver.init(n*m+2);
            for(int i=1;i<=n;++i){
                for(int j=1;j<=m;++j){
                    for(int k=0;k<4;++k){
                        int ni=i+dd[k][0],nj=j+dd[k][1];
                        if(ok(ni,nj)) solver.addEdge((i-1)*m+j,(ni-1)*m+nj,b);
                    }
                    if(p[i][j]=='#'){
                        if(i==1||i==n||j==1||j==m)
                            solver.addEdge(0,(i-1)*m+j,INF);
                        else
                            solver.addEdge(0,(i-1)*m+j,d);
                    }else{
                        solver.addEdge((i-1)*m+j,n*m+1,f);
                    }
                }
            }
            printf("%d
    ",solver.maxFlow(0,n*m+1)+cnt*f);
        }
        return 0;
    }
    

      

  • 相关阅读:
    厦门主要IT企业名单(至20071205)
    空,无
    扩展TextBox控件 荣
    我写的C++控件基类 荣
    扩展DataGrid 荣
    对重构的理解 荣
    C#中的委托与事件 荣
    CommunityServer中的代码页面分离 荣
    Oracle创建表空间,导出数据库,导入数据库 荣
    C#中的修饰符 荣
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/5107954.html
Copyright © 2020-2023  润新知