zoukankan      html  css  js  c++  java
  • P1935 [国家集训队]圈地计划 最小割

      

    题目描述

    最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地。据了解,这块土地是一块矩形的区域,可以纵横划分为N×M块小区域。GDOI要求将这些区域分为商业区和工业区来开发。根据不同的地形环境,每块小区域建造商业区和工业区能取得不同的经济价值。更具体点,对于第i行第j列的区域,建造商业区将得到Aij收益,建造工业区将得到Bij收益。另外不同的区域连在一起可以得到额外的收益,即如果区域(i,j)相邻(相邻是指两个格子有公共边)有k块(显然k不超过4)类型不同于(i,j)的区域,则这块区域能增加k×Cij收益。经过Tiger.S教授的勘察,收益矩阵A,B,C都已经知道了。你能帮GDOI求出一个收益最大的方案么?

    输入格式

    输入第一行为两个整数,分别为正整数N和M,分别表示区域的行数和列数;

    第2到N+1列,每行M个整数,表示商业区收益矩阵A;

    第N+2到2N+1列,每行M个整数,表示工业区收益矩阵B;

    第2N+2到3N+1行,每行M个整数,表示相邻额外收益矩阵C。

    输出格式

    输出只有一行,包含一个整数,为最大收益值。

    输入输出样例

    输入 #1
    3 3
    1 2 3
    4 5 6
    7 8 9
    9 8 7
    6 5 4
    3 2 1
    1 1 1
    1 3 1
    1 1 1
    输出 #1
    81


    题意: 有nm个点 每个点连A 可以的到aij的权值 连B 可以得到bij的权值 还有额外的权值: 每个点的周围和他选择的阵营不一样的有k个(显然小于4) 那么可以得到权值k*cij


    如果相同的话非常简单 和小m的作物一样

    但是可以将其转化为相邻的点选择相同时可以得到额外的权值
    只需要将矩阵棋盘染色 黑点的连接AB的方式与原来的图相反即可 (求得是最小割 毫无影响)
    那么就转为与相邻点阵营相同即可得到权值

    虽然图已经转化了 但是和小m的作物还是有一点不用的 这题是只要相同即可(不论选哪个阵营)

    可以考虑善意的投票那题

    相邻的点连一条双向边 因为这两个点如果不同会分别贡献两个值,所以这两个点之间的边为双向边,边权为这两个值相加

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define ll long long
    #define pb push_back
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    #define inf 0x3f3f3f3f
    const int N=4e5+44;
    const int M=4e6+54;
    int d[N];
    struct edge {
        int to, next, w;
    } e[M << 1];
    int head[N],cur[N],cnt = 1;
    void add(int x, int y, int z) {
        e[++cnt] = (edge){y, head[x], z};
        head[x] = cnt;
        e[++cnt] = (edge){x, head[y], 0};
        head[y] = cnt;
    }
    void ins(int x,int y,int a,int b)
    {
        add(x,y,b-a);
        d[x]-=a;
        d[y]+=a;
    }
    
    int level[N];
    bool bfs(int s, int t) {
        memset(level, 0, sizeof level);
        queue<int> q;
        level[s] = 1;
        q.push(s);
        while (!q.empty()) {
            int pos = q.front();q.pop();
            for (int i = head[pos]; i; i = e[i].next) {
                int nx = e[i].to;
                if (!e[i].w || level[nx]) continue;
                level[nx] = level[pos] + 1;
                q.push(nx);
            }
        }
        return level[t];
    }
    int dfs(int s, int t, int flow) {
        if(s==t||flow==0)return flow;
    
        int f,ret = 0;
        for (int &i = cur[s],v; i; i = e[i].next) {
             v = e[i].to;
            if (level[v] == level[s] + 1 && (f=dfs(v,t,min(flow,e[i].w)))>0) {
                e[i].w -= f;
                e[i ^ 1].w += f;
                flow -= f;
                ret += f;
                if(!flow)break;
            }
        }
        return ret;
    }
    int dinic(int s, int t) {
        int ret = 0;
        while (bfs(s, t)) memcpy(cur,head,sizeof cur),ret += dfs(s, t, inf);
        return ret;
    }
    int n,m,s,t,a,b,c,sum,S,T;
    
    int id(int x,int y)
    {
        return (x-1)*m+y;
    }
    
    int mp[200][200];
    int main()
    {
        cin>>n>>m;
        s=n*m+100;t=s+1;
    
        rep(i,1,n)
        rep(j,1,m)
        if( (i+j)&1 )
        scanf("%d",&a),add(s,id(i,j),a),sum+=a;
        else scanf("%d",&a),add(id(i,j),t,a),sum+=a;
    
        rep(i,1,n)
        rep(j,1,m)
        if( !((i+j)&1) )
        scanf("%d",&a),add(s,id(i,j),a),sum+=a;
        else scanf("%d",&a),add(id(i,j),t,a),sum+=a;
    
        rep(i,1,n)
        rep(j,1,m)scanf("%d",&mp[i][j]);
    
        int dx[]={1,-1,0,0};
        int dy[]={0,0,1,-1};
    
        rep(i,1,n)
        rep(j,1,m)
        {
            if( (i+j)&1 )continue;
    
            rep(k,0,3)
            {
                int x=i+dx[k];
                int y=j+dy[k];
                if(x<1||y<1||x>n||y>m)continue;
    
                add(id(i,j),id(x,y),mp[i][j]+mp[x][y]);
                add(id(x,y),id(i,j),mp[i][j]+mp[x][y]);
                sum+=mp[i][j]+mp[x][y];
            }
        }
        cout<<sum-dinic(s,t);
    
        return 0;
    }
    View Code
  • 相关阅读:
    BZOJ2243: [SDOI2011]染色(树链剖分/LCT)
    BZOJ2157: 旅游(LCT)
    BZOJ3510首都(LCT)
    BZOJ4530 [BJOI2014]大融合(LCT)
    BZOJ2631: tree(LCT)
    BZOJ2002: [Hnoi2010]Bounce 弹飞绵羊(LCT)
    BZOJ3282: Tree (LCT模板)
    [NOI2008]假面舞会(DFS)
    斜率优化dp练习
    BZOJ2049[Sdoi2008]Cave 洞穴勘测(LCT模板)
  • 原文地址:https://www.cnblogs.com/bxd123/p/11328457.html
Copyright © 2011-2022 走看看