BZOJ 3774: 最优选择( 最小割 )

最小割...二分染色然后把颜色不同的点的源汇反过来..然后就可以做了.

某个点(x,y):

S->Id(x,y)(回报), Id(x,y)->T(代价), Id(i,j)&&Id(相邻节点)->newId(i,j)(+oo), newId(i,j)->T(回报)

然后染色不同的点反过来就可以了.

初始时答案为2*∑回报, 这样每个点要么割掉1个回报,要么割掉2个回报, 要么割掉1回报+代价.都对应着每一种方案

--------------------------------------------------------------------------------

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cctype>

using namespace std;

#define Id(x, y) ((x) * M + (y))

#define chk(x, y) (0 <= (x) && (x) < N && 0 <= (y) && (y) < M)

const int maxn = 5009;

const int INF = 1 << 30;

const int dx[4] = {-1, 0, 0, 1};

const int dy[4] = {0, 1, -1, 0};

inline int read() {

char c = getchar();

int ret = 0;

for(; !isdigit(c); c = getchar());

for(; isdigit(c); c = getchar()) ret = ret * 10 + c - ‘0‘;

return ret;

}

struct edge {

int to, cap;

edge *next, *rev;

} E[5000000], *pt = E, *head[maxn], *p[maxn], *cur[maxn];

inline void Add(int u, int v, int w) {

pt->to = v;

pt->cap = w;

pt->next = head[u];

head[u] = pt++;

}

inline void AddEdge(int u, int v, int w) {

Add(u, v, w);

Add(v, u, 0);

head[u]->rev = head[v];

head[v]->rev = head[u];

}

int N, M, S, T, V, ans;

int h[maxn], cnt[maxn];

void Solve() {

for(int i = 0; i < V; i++) cur[i] = head[i];

memset(cnt, 0, sizeof cnt);

memset(h, 0, sizeof h);

cnt[0] = V;

edge* e;

int Flow = 0;

for(int x = S, A = INF; h[S] < V; ) {

for(e = cur[x]; e; e = e->next)

if(e->cap && h[e->to] + 1 == h[x]) break;

if(e) {

A = min(A, e->cap);

cur[x] = p[e->to] = e;

if((x = e->to) == T) {

for(; x != S; x = p[x]->rev->to) {

p[x]->cap -= A;

p[x]->rev->cap += A;

}

Flow += A;

A = INF;

}

} else {

if(!--cnt[h[x]]) break;

h[x] = V;

for(e = head[x]; e; e = e->next) if(e->cap && h[e->to] + 1 < h[x]) {

h[x] = h[e->to] + 1;

cur[x] = e;

}

cnt[h[x]]++;

if(x != S)

x = p[x]->rev->to;

}

}

printf("%d\n", (ans << 1) - Flow);

}

void Init() {

N = read(); M = read();

V = N * M; S = V++; T = V++;

for(int i = 0; i < N; i++)

for(int j = 0; j < M; j++)

(i + j) & 1 ? AddEdge(Id(i, j), T, read()) : AddEdge(S, Id(i, j), read());

ans = 0;

for(int i = 0; i < N; i++)

for(int j = 0; j < M; j++) {

int v = read(), np = V++;

ans += v;

if((i + j) & 1) {

AddEdge(S, Id(i, j), v);

AddEdge(np, T, v);

AddEdge(Id(i, j), np, INF);

for(int k = 0; k < 4; k++) {

int x = i + dx[k], y = j + dy[k];

if(chk(x, y))

AddEdge(Id(x, y), np, INF);

}

} else {

AddEdge(Id(i, j), T, v);

AddEdge(S, np, v);

AddEdge(np, Id(i, j), INF);

for(int k = 0; k < 4; k++) {

int x = i + dx[k], y = j + dy[k];

if(chk(x, y))

AddEdge(np, Id(x, y), INF);

}

}

}

}

int main() {

Init();

Solve();

return 0;

}

--------------------------------------------------------------------------------

3774: 最优选择

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 96  Solved: 48
[Submit][Status][Discuss]

Description

小N手上有一个N*M的方格图,控制某一个点要付出Aij的代价,然后某个点如果被控制了,或者他周围的所有点(上下左右)都被控制了,那么他就算是被选择了的。一个点如果被选择了,那么可以得到Bij的回报,现在请你帮小N选一个最优的方案,使得回报-代价尽可能大。

Input

第一行两个正整数N,M表示方格图的长与宽。

接下来N行每行M个整数Aij表示控制的代价。

接下来N行每行M个整数Bij表示选择的回报。

Output

一个整数,表示最大的回报-代价(如果一个都不控制那么就是0)。

Sample Input

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

Sample Output

8

HINT

对于100%的数据,N,M<=50,Aij,Bij都是小于等于100的正整数。

Source

时间: 2024-08-04 14:21:11

BZOJ 3774: 最优选择( 最小割 )的相关文章

[BZOJ 3774] 最优选择 【最小割】

题目链接:BZOJ - 3774 题目分析 此题与“文理分科”那道题目有些类似.都是使用最小割来求解,先加上可能获得的权值,在减掉必须舍弃的权值(最小割). 文理分科是规定每个人和 S 连就是选文,和 T 连就是选理.然后如果一个人和相邻的人都全文就会获得一个权值,那么我们就为这个权值建一个点,让这个点与必须同时选文的5个人连 INF 边.这样只要这 5 个人中有一个人选了理,就必须舍弃这个权值了. 再回到这道题目,这道题获得权值的条件是这个点被控制或这个点相邻的 4 个点都被控制. 这个“或”

【BZOJ3774】最优选择 最小割

[BZOJ3774]最优选择 Description 小N手上有一个N*M的方格图,控制某一个点要付出Aij的代价,然后某个点如果被控制了,或者他周围的所有点(上下左右)都被控制了,那么他就算是被选择了的.一个点如果被选择了,那么可以得到Bij的回报,现在请你帮小N选一个最优的方案,使得回报-代价尽可能大. Input 第一行两个正整数N,M表示方格图的长与宽. 接下来N行每行M个整数Aij表示控制的代价. 接下来N行每行M个整数Bij表示选择的回报. Output 一个整数,表示最大的回报-代

BZOJ 2007 海拔(平面图最小割-最短路)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2007 题意:给出一个n*n的格子,那么顶点显然有(n+1)*(n+1)个.每两个相邻顶点之间有两条边,这两条边是有向的,边上有权值..左上角为源点,右下角为汇点,求s到t的最小割. 思路:很明显这是一个平面图,将其转化为最 短路.我们将s到t之间连一条边,左下角为新图的源点S,右上角区域为新图的终点T,并且为每个格子编号.由于边是有向的,我们就要分析下这条边应该是哪 个点向哪个点的边.

ZOJ 2676 Network Wars(最优比例最小割)

Network Wars Time Limit: 5 Seconds      Memory Limit: 32768 KB      Special Judge Network of Byteland consists of n servers, connected by m optical cables. Each cable connects two servers and can transmit data in both directions. Two servers of the n

BZOJ 2132 圈地计划 最小割

题目大意:给定一个m*n的矩阵,每个位置如果作为商业区或者工业区各有一个收益,如果相邻两块是不同的也会有一个收益,求最大收益 吐槽:住宅区呢- - 地理老师骗我们- - 普通的最小割建图会遇到一个问题: 割断两块之间的边收益为正,即代价为负 因此我们如果正常建最小割,那么两块之间的边权就会是负的 那么我们将这个矩阵黑白染色,将白格ST反向 这样割断两块之间的连边相当于两块选择了同一用途,代价为正 就可以正常跑了 #include <cstdio> #include <cstring>

[BZOJ 3144] [Hnoi2013] 切糕 【最小割】

题目链接:BZOJ - 3144 题目分析 题意:在 P * Q 的方格上填数字,可以填 [1, R] . 在 (x, y) 上填 z 会有 V[x][y][z] 的代价.限制:相邻两个格子填的数字的差的绝对值不能超过 D . 求一个合法的最小总代价. 这道题是一个最小割模型,直接说建图吧. 建图:每个点 (x, y) 拆成 R 个点,(x, y, z) 代表 (x, y) 填 z. 然后从 S 向 (*, *, 1) 连 INF ,从 (*, *, R) 向 T 连 INF . 然后对于 (i

[BZOJ 3894] 文理分科 【最小割】

题目链接:BZOJ - 3894 题目分析 最小割模型,设定一个点与 S 相连表示选文,与 T 相连表示选理. 那么首先要加上所有可能获得的权值,然后减去最小割,即不能获得的权值. 那么对于每个点,从 S 向它连权值为它选文的价值的边,从它向 T 连权值为它选理的价值的边. 对于一个点,它和与它相邻的点构成了一个集合,这个集合如果都选文,可以获得一个价值v1,如果都选理,可以获得一个价值 v2. 只要这个集合中有一个点选文,就无法获得 v2,只要有一个点选理,就无法获得 v1. 那么处理方式就是

BZOJ 3144 HNOI 2013 切糕 最小割

题目大意:给出一个三维的点阵,没个点都有可能被切割,代价就是这个点的权值.相邻的切割点的高度差不能超过D,问最小的花费使得上下分开. 思路:很裸的最小割模型,很神的建图. S->第一层的点,f:INF 所有点->它下面的点,f:INF 一个点的入->一个点的出,f:val[i] (i,j,k) - > (i - d,j,k),f:INF 最下面一层的点->T:f:INF 然后跑最小割就是答案. 为什么见:http://www.cnblogs.com/zyfzyf/p/4182

BZOJ 3275 Number &amp;&amp; 3158 千钧一发 最小割

题目大意:给出一些数字,要求选出一些数字并保证所有数字和最大,要求这其中的数字任意两个至少满足一个条件,则不能同时被选:1.这两个数的平方和是完全平方数.2.gcd(a,b) = 1. 思路:我们可以将奇数和偶数分开来讨论,奇数不满足1,偶数不满足2,所以奇数和奇数,偶数和偶数不会互相影响.之后O(n^2)的讨论其他数字对,有影响就连边,流量正无穷,最后跑最小割最最大获利. CODE: #define _CRT_SECURE_NO_WARNINGS #include <cmath> #incl