最小割..
S连每个人(容量:选择理科的愉悦);每个人连T(容量:选择理科的愉悦) .
对于每一组(x, y, w)x和y同选理增加的愉悦w,新建节点V,V连x(INF),V连y(INF), S连V(w)
对于每一组(x, y, w)x和y同选文增加的愉悦w,新建节点V,x连V(INF),y连V(INF), V连T(w)
-------------------------------------------------------------------
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int maxn = 60000;
const int INF = 100000000;
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;
}
int N, M, S, T, V, tot = 0;
struct edge {
int to, cap;
edge *next, *rev;
} E[10000000], *pt = E, *head[maxn];
void Add(int u, int v, int w) {
pt->to = v; pt->cap = w; pt->next = head[u]; head[u] = pt++;
}
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];
}
edge *p[maxn], *cur[maxn];
int h[maxn], cnt[maxn];
int maxFlow() {
memset(cnt, 0, sizeof cnt);
memset(h, 0, sizeof h);
for(int i = 0; i < V; i++)
cur[i] = head[i];
cnt[0] = V;
int Flow = 0;
edge* e;
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) {
p[e->to] = cur[x] = e;
A = min(A, e->cap);
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(h[e->to] + 1 < h[x] && e->cap) {
h[x] = h[e->to] + 1;
cur[x] = e;
}
cnt[h[x]]++;
if(x != S)
x = p[x]->rev->to;
}
}
return Flow;
}
void Init() {
scanf("%d%d", &N, &M);
S = N * M; T = S + 1;
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++) {
int v = read();
tot += v;
AddEdge(i * M + j, T, v);
}
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++) {
int v = read();
tot += v;
AddEdge(S, i * M + j, v);
}
V = T;
for(int i = 1; i < N; i++)
for(int j = 0; j < M; j++) {
int v = read();
tot += v;
AddEdge(++V, T, v);
AddEdge(i * M + j, V, INF);
AddEdge((i - 1) * M + j, V, INF);
}
for(int i = 1; i < N; i++)
for(int j = 0; j < M; j++) {
int v = read();
tot += v;
AddEdge(S, ++V, v);
AddEdge(V, i * M + j, INF);
AddEdge(V, (i - 1) * M + j, INF);
}
for(int i = 0; i < N; i++)
for(int j = 1; j < M; j++) {
int v = read();
tot += v;
AddEdge(++V, T, v);
AddEdge(i * M + j, V, INF);
AddEdge(i * M + j - 1, V, INF);
}
for(int i = 0; i < N; i++)
for(int j = 1; j < M; j++) {
int v = read();
tot += v;
AddEdge(S, ++V, v);
AddEdge(V, i * M + j, INF);
AddEdge(V, i * M + j - 1, INF);
}
++V;
}
int main() {
Init();
printf("%d\n", tot - maxFlow());
return 0;
}
-------------------------------------------------------------------
2127: happiness
Time Limit: 51 Sec Memory Limit: 259 MB
Submit: 1119 Solved: 530
[Submit][Status][Discuss]Description
高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。
Input
第一行两个正整数n,m。接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值。第二个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择理科获得的喜悦值。第三个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择文科获得的额外喜悦值。第四个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择理科获得的额外喜悦值。第五个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择文科获得的额外喜悦值。第六个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择理科获得的额外喜悦值。
Output
Sample Input
1 2
1 1
100 110
1
1000
Sample Output
1210
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数
HINT
Source