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
  • 相关阅读:
    mac os programming
    Rejecting Good Engineers?
    Do Undergrads in MIT Struggle to Obtain Good Grades?
    Go to industry?
    LaTex Tricks
    Convert jupyter notebooks to python files
    How to get gradients with respect to the inputs in pytorch
    Uninstall cuda 9.1 and install cuda 8.0
    How to edit codes on the server which runs jupyter notebook using your pc's bwroser
    Leetcode No.94 Binary Tree Inorder Traversal二叉树中序遍历(c++实现)
  • 原文地址:https://www.cnblogs.com/bxd123/p/11328457.html
Copyright © 2011-2022 走看看