HOJ 2713 Matrix1 [網絡流] 最大點權獨立集問題

題目: LINK

題目大意: 一個 N*M 的網格,每個單元都有一塊價值 Cij 的寶石。問最多能取多少價值的寶石且任意兩塊寶石不相鄰。(1 <= N, M <= 50, 0 <= Cij <= 40000)
    最大點權獨立集問題
    先將網格黑白染色,從源點S到每個黑點有一條邊,從每個白點到匯點T有一條邊,容量均爲相應寶石的價值。
每個黑點向與其相鄰的四個白點連邊,容量爲∞。設最小割爲 ans,結果即爲∑Cij – ans。
 因爲每一個割都會對應一個方案。假設割爲[S,T],割上的邊要麼與S連接,要麼與T連接,因爲其他邊都爲∞。
 割會分割成兩部分含S的部分 和 含T的部分,兩部分不相連接,我們取的點就是 和S相連的黑點的值A' + 和T點相連的白點的值B'。
結果= A' + B' = sum - [S, T]; 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std; 
#define INF 1000000000
//typedef __int64 LL; 
#define N 3333
int t, n, m, lev[N], tot, hh[N], num[55][55], S, T, ids[55][55]; 
struct node {
    int u, v, w, next; 
}edge[1000001]; 
int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0}; 
void init() {
    memset(hh, -1, sizeof(hh)); 
    tot = 0; 
}
void add(int u, int v, int w) {
    edge[tot].u = u; edge[tot].v = v; 
    edge[tot].w = w; edge[tot].next = hh[u]; 
    hh[u] = tot ++; 
}
int test(int x, int y ) {
    if(x < 1 || x > n || y < 1 || y > m) return 0; 
    return 1; 
}
int bfs() {
    queue<int > Q; 
    memset(lev, -1, sizeof(lev)); 
    Q.push(S); lev[S] = 0; 
    while(!Q.empty()) {
        int u = Q.front(); Q.pop(); 
        for(int i = hh[u]; i != -1; i = edge[i].next) {
            int v = edge[i].v; 
            if(edge[i].w && lev[v] == -1) {
                lev[v] = lev[u] + 1; 
                Q.push(v); 
            }
        }
    }
    return lev[T] != -1; 
}
int dfs(int u, int flow) {
    if(u == T) return flow; 
    int tmp = flow, ad; 
    for(int i = hh[u]; i != -1; i = edge[i].next) {
        int v = edge[i].v; 
        if(lev[v] == lev[u] + 1 && tmp > 0 && edge[i].w) {
            ad = dfs(v, min(tmp, edge[i].w)); 
            if(!tmp) break; 
            edge[i].w -= ad; 
            edge[i^1].w += ad; 
            tmp -= ad; 
        }
    }
    if(ad == 0) lev[u] = -1; 
    return flow- tmp; 
}
int dinic() {
    int ret = 0, tmp; 
    while(bfs())  while(tmp = dfs(S, INF)) ret += tmp;  
    return ret; 
}
int main() 
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin); 
#endif // ONLINE_JUDGE
    scanf("%d", &t); 
    while(t --) {
        scanf("%d%d", &n, &m); 
        int id = 0, sum = 0; 
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                ++ id; 
                scanf("%d", &num[i][j]); 
                sum += num[i][j]; 
                ids[i][j] = id; 
            }
        }
        init(); 
        S = 0; T = n*m + 2; 
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                int mark = (i+j) & 1; 
                id = ids[i][j]; 
                if(mark) {
                    add(id, T, num[i][j]); add(T, id, 0); 
                }
                else {
                    add(S, id, num[i][j]); add(id, S, 0); 
                    for(int k = 0; k < 4; k++) {
                        int nx = i + dir[k][0]; 
                        int ny = j + dir[k][1]; 
                        int tmp = test(nx, ny); 
                        if(!tmp) continue; 
                        add(id, ids[nx][ny], INF); add(ids[nx][ny], id, 0); 
                    }
                }
            }
        }
        int ans = dinic(); 
        printf("%d\n", sum - ans); 
    }
    return 0; 
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章