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; 
}


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