bzoj2132 圈地計劃

bzoj2132 圈地計劃

Description
最近房地產商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求出一個收益最大的方案麼?

Input
輸入第一行爲兩個整數,分別爲正整數N和M,分別表示區域的行數和列數;第2到N+1列,每行M個整數,表示商業區收益矩陣A;第N+2到2N+1列,每行M個整數,表示工業區收益矩陣B;第2N+2到3N+1行,每行M個整數,表示相鄰額外收益矩陣C。第一行,兩個整數,分別是n和m(1≤n,m≤100);
任何數字不超過1000的限制

Output
輸出只有一行,包含一個整數,爲最大收益值。

Sample Input
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

Sample Output
81

【數據規模】
對於100%的數據有N,M≤100

我覺得這個題意不錯.. 特別是前兩句

這道題還是挺裸的.. 就是把這個n*m的圖按照點的橫縱座標特徵黑白染色,黑的連源匯正好與白的連源匯相反,然後會產生額外費用的相鄰點再中間連邊,最後做一次最小割即可

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
using namespace std;
const int Maxn = 110;
const int dx[4] = { 0, 1, 0, -1 };
const int dy[4] = { 1, 0, -1, 0 };
struct node {
    int x, y, next, c, opp;
}a[Maxn*Maxn*20]; int first[Maxn*Maxn], len;
int _min ( int x, int y ){ return x < y ? x : y; }
void ins ( int x, int y, int c ){
    len ++; int k1 = len;
    a[len].x = x; a[len].y = y; a[len].c = c;
    a[len].next = first[x]; first[x] = len;
    len ++; int k2 = len;
    a[len].x = y; a[len].y = x; a[len].c = 0;
    a[len].next = first[y]; first[y] = len;
    a[k1].opp = k2;
    a[k2].opp = k1;
}
int st, ed, h[Maxn*Maxn];
int n, m;
int na[Maxn][Maxn];
int getnum ( int x, int y ){ return (x-1)*m+y; }
bool bfs (){
    queue <int> q;
    memset ( h, -1, sizeof (h) );
    q.push (st); h[st] = 0;
    while ( !q.empty () ){
        int x = q.front (); q.pop ();
        for ( int k = first[x]; k; k = a[k].next ){
            int y = a[k].y;
            if ( h[y] == -1 && a[k].c > 0 ){
                h[y] = h[x]+1;
                q.push (y);
            }
        }
    }
    return h[ed] > 0;
}
int dfs ( int x, int flow ){
    if ( x == ed ) return flow;
    int delta = 0;
    for ( int k = first[x]; k; k = a[k].next ){
        int y = a[k].y;
        if ( h[y] == h[x]+1 && a[k].c > 0 && flow-delta > 0 ){
            int minf = dfs ( y, _min ( a[k].c, flow-delta ) );
            delta += minf;
            a[k].c -= minf;
            a[a[k].opp].c += minf;
        }
    }
    if ( delta == 0 ) h[x] = -1;
    return delta;
}
int main (){
    int i, j, k;
    scanf ( "%d%d", &n, &m );
    len = 0; memset ( first, 0, sizeof (first) );
    st = 0; ed = n*m+1;
    int sum = 0;
    for ( i = 1; i <= n; i ++ ){
        for ( j = 1; j <= m; j ++ ){
            int x;
            scanf ( "%d", &x );
            sum += x;
            if ( (i+j) % 2 == 1 ) ins ( st, getnum (i,j), x );
            else ins ( getnum (i,j), ed, x );
        }
    }
    for ( i = 1; i <= n; i ++ ){
        for ( j = 1; j <= m; j ++ ){
            int x;
            scanf ( "%d", &x );
            sum += x;
            if ( (i+j) % 2 == 1 ) ins ( getnum (i,j), ed, x );
            else ins ( st, getnum (i,j), x );
        }
    }
    for ( i = 1; i <= n; i ++ ){
        for ( j = 1; j <= m; j ++ ){
            scanf ( "%d", &na[i][j] );
        }
    }
    for ( i = 1; i <= n; i ++ ){
        for ( j = 1; j <= m; j ++ ){
            for ( k = 0; k < 4; k ++ ){
                int ii = i+dx[k], jj = j+dy[k];
                if ( ii < 1 || ii > n || jj < 1 || jj > m ) continue;
                sum += na[i][j];
                ins ( getnum (i,j), getnum (ii,jj), na[i][j]+na[ii][jj] );
            }
        }
    }
    int ans = 0, delta;
    while ( bfs () ){
        while ( delta = dfs ( st, 0x7fffffff ) ) ans += delta;
    }
    printf ( "%d\n", sum-ans );
    return 0;
}
發佈了56 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章