1. 程式人生 > >【bzoj3774】最優選擇 網絡流最小割

【bzoj3774】最優選擇 網絡流最小割

bubuko nic ret 選擇 整數 CP 左右 log dinic

題目描述

小N手上有一個N*M的方格圖,控制某一個點要付出Aij的代價,然後某個點如果被控制了,或者他周圍的所有點(上下左右)都被控制了,那麽他就算是被選擇了的。一個點如果被選擇了,那麽可以得到Bij的回報,現在請你幫小N選一個最優的方案,使得回報-代價盡可能大。

輸入

第一行兩個正整數N,M表示方格圖的長與寬。

接下來N行每行M個整數Aij表示控制的代價。

接下來N行每行M個整數Bij表示選擇的回報。

輸出

一個整數,表示最大的回報-代價(如果一個都不控制那麽就是0)。

樣例輸入

3 3
1 100 100
100 1 100
1 100 100
2 0 0
5 2 0
2 0 0

樣例輸出

8


題解

網絡流最小割

先求出所有價值的總和,然後對於每個點:要麽付出選擇代價,要麽放棄價值,要麽相鄰點付出選擇代價。

考慮構建a-b-inf-a‘的結構。

每個點拆成兩個(以下稱1和2),中間連容量為b的邊,表示價值。將原圖黑白染色,對於黑點:S向1連邊,容量為a;對於白點:2向T連邊,容量為a,表示付出選擇代價。

對於黑點:該點的2向相鄰點(顯然是白點)的2連邊,容量為inf,這樣就有了a-b-inf-a‘的結構;對於白點:相鄰點的1向該點的1連邊,容量為inf,這樣就有了a‘-inf-b-a的結構。

建出來的圖大概長這樣(B為黑點,W為白點):

技術分享圖片

總收益減去最小割即為答案。

#include <queue>
#include <cstdio>
#include <cstring>
#define N 5010
#define M 100010
#define inf 1 << 30
#define pos(h , i , j) ((h - 1) * n * m + (i - 1) * m + j)
using namespace std;
queue<int> q;
int head[N] , to[M] , val[M] , next[M] , cnt = 1 , s , t , dis[N];
inline void add(int x , int y , int z)
{
	to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
	to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
}
bool bfs()
{
	int x , i;
	memset(dis , 0 , sizeof(dis));
	while(!q.empty()) q.pop();
	dis[s] = 1 , q.push(s);
	while(!q.empty())
	{
		x = q.front() , q.pop();
		for(i = head[x] ; i ; i = next[i])
		{
			if(val[i] && !dis[to[i]])
			{
				dis[to[i]] = dis[x] + 1;
				if(to[i] == t) return 1;
				q.push(to[i]);
			}
		}
	}
	return 0;
}
int dinic(int x , int low)
{
	if(x == t) return low;
	int temp = low , i , k;
	for(i = head[x] ; i ; i = next[i])
	{
		if(val[i] && dis[to[i]] == dis[x] + 1)
		{
			k = dinic(to[i] , min(temp , val[i]));
			if(!k) dis[to[i]] = 0;
			val[i] -= k , val[i ^ 1] += k;
			if(!(temp -= k)) break;
		}
	}
	return low - temp;
}
int main()
{
	int n , m , i , j , x , ans = 0;
	scanf("%d%d" , &n , &m) , s = 0 , t = 2 * n * m + 1;
	for(i = 1 ; i <= n ; i ++ )
	{
		for(j = 1 ; j <= m ; j ++ )
		{
			scanf("%d" , &x);
			if((i ^ j) & 1)
			{
				add(s , pos(1 , i , j) , x);
				if(i > 1) add(pos(1 , i , j) , pos(1 , i - 1 , j) , inf) , add(pos(2 , i , j) , pos(2 , i - 1 , j) , inf);
				if(i < n) add(pos(1 , i , j) , pos(1 , i + 1 , j) , inf) , add(pos(2 , i , j) , pos(2 , i + 1 , j) , inf);
				if(j > 1) add(pos(1 , i , j) , pos(1 , i , j - 1) , inf) , add(pos(2 , i , j) , pos(2 , i , j - 1) , inf);
				if(j < m) add(pos(1 , i , j) , pos(1 , i , j + 1) , inf) , add(pos(2 , i , j) , pos(2 , i , j + 1) , inf);
			}
			else add(pos(2 , i , j) , t , x);
		}
	}
	for(i = 1 ; i <= n ; i ++ )
		for(j = 1 ; j <= m ; j ++ )
			scanf("%d" , &x) , add(pos(1 , i , j) , pos(2 , i , j) , x) , ans += x;
	while(bfs()) ans -= dinic(s , inf);
	printf("%d\n" , ans);
	return 0;
}

【bzoj3774】最優選擇 網絡流最小割