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;
}

  

原文地址:https://www.cnblogs.com/20143605--pcx/p/5107954.html