方格取数问题(二分图点权最大独立集)

//http://www.cnblogs.com/IMGavin/
#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

const int INF = 0x3F3F3F3F, N = 1000008, MOD = 1003, M = 1000000;

const double EPS = 1e-6;

int dir[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0}};

int head[N], tot;

struct node{
	int u, v, cap, next;
}edge[M];
int cur[N], lev[N], s[N];

void init(){
	memset(head, -1, sizeof(head));
	tot = 0;
}

void add(int u, int v, int cap){
	edge[tot].u = u;
	edge[tot].v = v;
	edge[tot].cap = cap;
	edge[tot].next = head[u];
	head[u] = tot++;
//反向弧
	edge[tot].u = v;
	edge[tot].v = u;
	edge[tot].cap = 0;
	edge[tot].next = head[v];
	head[v] = tot++;
}

bool bfs(int st, int des){
	memset(lev, -1, sizeof(lev));
	lev[st] = 0;
	queue<int> q;
	q.push(st);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		for(int i = head[u]; i != -1; i = edge[i].next){
			int v = edge[i].v;
			if(edge[i].cap && lev[v] == -1){
				lev[v] = lev[u] + 1;
				q.push(v);
				if(v == des){
					return true;
				}
			}
		}
	}
	return false;
}
//源点,汇点,点的数量
int dinic(int st, int des, int n){
	int ans = 0;
	while(bfs(st, des)){
		memcpy(cur, head, sizeof(int) * (n + 1));
		int u = st, top = 0;
		while(true){
			if(u == des){
				int mini = INF, loc;
				for(int i = 0; i < top; i++){
					if(mini > edge[s[i]].cap){
						mini = edge[s[i]].cap;
						loc = i;
					}
				}
				for(int i = 0; i < top; i++){
					edge[s[i]].cap -= mini;
					edge[s[i] ^ 1].cap += mini;
				}
				ans += mini;
				top = loc;
				u = edge[s[top]].u;
			}
			int &i = cur[u];//引用类型
			for(; i != -1; i = edge[i].next){
				int v = edge[i].v;
				if(edge[i].cap && lev[v] == lev[u] + 1){
					break;
				}
			}
			if(i != -1){
				s[top++] = i;
				u = edge[i].v;
			}else{
				if(!top){
					break;
				}
				lev[u] = -1;
				u = edge[s[--top]].u;
			}
		}
	}
	return ans;
}
int main(){
	int m, n;
	while(cin >> m >> n){
		init();
		int st = m * n, des = m * n + 1;
		int sum = 0;
		for(int i = 0; i < m; i++){
			for(int j = 0; j < n; j++){
				int val;
				scanf("%d", &val);
				sum += val;
				if(((i + j) & 1) == 0){
					add(st, i * n + j, val);
					for(int k = 0; k < 4; k++){
						int x = i + dir[k][0], y = j + dir[k][1];
						if(x >= 0 && y >= 0 && x < m && y < n){
							add(i * n + j, x * n + y, INF);
						}
					}
				}else{
					add(i * n + j, des, val);
				}
			}
		}
		printf("%d
", sum - dinic(st, des, des + 1));

	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/IMGavin/p/6385768.html