zoukankan      html  css  js  c++  java
  • BZOJ 2132 圈地计划(最小割)

    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2132

    【题目大意】

      给出一块n*m的地,每个格子如果开发成商业区,则收益为Aij,若开发为工业区则收入Bij,
      如果一个格子周围有和其不一样种类的地,那么能增加额外收益k*Cij,其中k为不同的地块数

    【题解】

      我们先将所有的收益全都连上,根据i+j的奇偶性将图变为二分图,
      对于i+j为奇数的我们连Aij到源点,Bij到汇点,为偶数的我们连Aij到汇点,Bij到源点。
      图的总权值减去图的最小割就是答案。

    【代码】

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    using namespace std;
    const int INF=0x3f3f3f3f;
    const int MAX_V=20010;
    struct edge{int to,cap,rev;}; 
    vector<edge> G[MAX_V];
    int level[MAX_V],iter[MAX_V];
    void add_edge(int from,int to,int cap){
        G[from].push_back((edge){to,cap,G[to].size()});
        G[to].push_back((edge){from,0,G[from].size()-1});
    }
    void bfs(int s){
        memset(level,-1,sizeof(level));
        queue<int> que;
        level[s]=0;
        que.push(s);
        while(!que.empty()){
            int v=que.front(); que.pop();
            for(int i=0;i<G[v].size();i++){
                edge &e=G[v][i];
                if(e.cap>0&&level[e.to]<0){
                    level[e.to]=level[v]+1;
                    que.push(e.to);
                }
            }
        }
    }
    int dfs(int v,int t,int f){
        if(v==t)return f;
        for(int &i=iter[v];i<G[v].size();i++){
            edge &e=G[v][i];
            if(e.cap>0&&level[v]<level[e.to]){
                int d=dfs(e.to,t,min(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    G[e.to][e.rev].cap+=d;
                    return d;
                }
            }
        }return 0;
    }
    int max_flow(int s,int t){
        int flow=0;
        for(;;){
            bfs(s);
            if(level[t]<0)return flow;
            memset(iter,0,sizeof(iter));
            int f;
            while((f=dfs(s,t,INF))>0){
                flow+=f;
            }
        }
    }
    int mp[110][110],x,n,m;
    const int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
    bool check(int x,int y){return x>=0&&y>=0&&x<n&&y<m;}
    int main(){
        while(~scanf("%d%d",&n,&m)){
            int s=n*m*2,t=s+1,tot=0;
            for(int i=0;i<=t;i++)G[i].clear();
            for(int i=0;i<n;i++)for(int j=0;j<m;j++){
                scanf("%d",&x);tot+=x;
                if((i+j)%2)add_edge(s,i*m+j,x);
                else add_edge(i*m+j,t,x);
            }
            for(int i=0;i<n;i++)for(int j=0;j<m;j++){
                scanf("%d",&x);tot+=x;
                if((i+j)%2)add_edge(i*m+j,t,x);
                else add_edge(s,i*m+j,x);
            }
            for(int i=0;i<n;i++)for(int j=0;j<m;j++)scanf("%d",&mp[i][j]);
            for(int i=0;i<n;i++)for(int j=0;j<m;j++){
                if((i+j)%2)for(int k=0;k<4;k++){
                    int x=i+dx[k],y=j+dy[k];
                    if(check(x,y)){
                        add_edge(i*m+j,x*m+y,mp[x][y]+mp[i][j]);
                        add_edge(x*m+y,i*m+j,mp[x][y]+mp[i][j]);
                        tot+=mp[x][y]+mp[i][j];
                    }
                }
            }printf("%d
    ",tot-max_flow(s,t));
        }return 0;
    }
  • 相关阅读:
    hdu 1042 N!
    hdu 1002 A + B Problem II
    c++大数模板
    hdu 1004 Let the Balloon Rise
    hdu 4027 Can you answer these queries?
    poj 2823 Sliding Window
    hdu 3074 Multiply game
    hdu 1394 Minimum Inversion Number
    hdu 5199 Gunner
    九度oj 1521 二叉树的镜像
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj2132.html
Copyright © 2011-2022 走看看