大家都很强, 可与之共勉。
3894: 文理分科
Description
文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠
结过)
小P所在的班级要进行文理分科。他的班级可以用一个n*m的矩阵进行
描述,每个格子代表一个同学的座位。每位同学必须从文科和理科中选择
一科。同学们在选择科目的时候会获得一个满意值。满意值按如下的方式
得到:
1.如果第i行第秒J的同学选择了文科,则他将获得art[i][j]的满意值,如
果选择理科,将得到science[i][j]的满意值。
2.如果第i行第J列的同学选择了文科,并且他相邻(两个格子相邻当且
仅当它们拥有一条相同的边)的同学全部选择了文科,则他会更开
心,所以会增加same_art[i][j]的满意值。
3.如果第i行第j列的同学选择了理科,并且他相邻的同学全部选择了理
科,则增加same_science[i]j[]的满意值。
小P想知道,大家应该如何选择,才能使所有人的满意值之和最大。请
告诉他这个最大值。
Input
第一行为两个正整数:n,m
接下来n术m个整数,表示art[i][j];
接下来n术m个整数.表示science[i][j];
接下来n术m个整数,表示same_art[i][j];
Output
输出为一个整数,表示最大的满意值之和
Sample Input
3 4
13 2 4 13
7 13 8 12
18 17 0 5
8 13 15 4
11 3 8 11
11 18 6 5
1 2 3 4
4 2 3 2
3 1 0 4
3 2 3 2
0 2 2 1
0 2 4 4
Sample Output
152
HINT
个人觉得他的输入描述很不堪。。。
令S集为学文,T集为学理, 每个人学文或者学理的满意度很好连边,
如果某个集合内的人都学理会获得一个满意度,那么就新加一个点,将集合内的所有人向这个点连流量为正无穷的边, 再从这个点向T连一条流量为满意度的边, 表示集合内任意一个人学文都要把这个点与T的边割掉。
都学文同理
盗一张ZWD的图
建完图之后跑最小割即可
/**************************************************************
Problem: 3894
User: Lazer2001
Language: C++
Result: Accepted
Time:1996 ms
Memory:13012 kb
****************************************************************/
#include <cstdio>
#include <cstring>
#define Inf 0x3f3f3f3f
#define max( a, b ) ((a) > (b) ? (a) : (b))
#define min( a, b ) ((a) < (b) ? (a) : (b))
typedef class EdgeData {
public:
int to, w, nxt ;
EdgeData ( ) { }
EdgeData ( int to, int w, int nxt ) : to ( to ), w ( w ), nxt ( nxt ) { }
} Edge ;
Edge G[1000005] ;
int ne = 1, head[30005] ;
int n, m, x, ans;
const int S = 0, T = 30004;
const int dx[] = { 0, 0, 0, 1, -1 } ;
const int dy[] = { 0, 1, -1, 0, 0 } ;
#define P(x, y) ((x - 1) * (m) + (y))
#define Adde( u, v, w ) ; { G[++ ne] = Edge ( v, w, head[u] ) ; head[u] = ne ; }
inline void AddDbe ( int u, int v, int w ) {
Adde ( u, v, w ) ; Adde ( v, u, 0 ) ;
}
class Network_Flows {
private:
int S, T, ret ;
int cur[30005], dep[30005] ;
inline short Bfs ( ) {
static int fr, tl, q[30005] ;
static int u, v;
memset ( dep, 0, sizeof ( int ) * ( T + 1 ) ) ;
fr = tl = 0 ;
q[++ tl] = S ;
dep[S] = 1 ;
while ( fr ^ tl ) {
u = q[++ fr] ;
for ( int i = head[u] ; i ; i = G[i].nxt ) {
v = G[i].to;
if ( G[i].w && !dep[v] ) {
dep[v] = dep[u] + 1 ;
q[++ tl] = v ;
}
}
}
return dep[T] != 0 ;
}
int Dfs ( int u, int a ) {
if ( u == T || !a ) return a ;
int v, f, flow = 0 ;
for( int& i = cur[u] ; i ; i = G[i].nxt ) {
v = G[i].to ;
if ( dep[v] == dep[u] + 1 ) {
f = Dfs ( v, min( a - flow, G[i].w ) ) ;
G[i].w -= f ; G[i ^ 1].w += f ;
flow += f ;
if ( flow == a ) return flow ;
}
}
if ( !flow ) dep[u] = -1 ; // cannot be 0;
return flow;
}
public:
inline int Dinic ( int S, int T ) {
this -> S = S, this -> T = T ;
ret = 0 ;
while ( Bfs ( ) ) {
memcpy ( cur, head, sizeof ( int ) * ( T + 1 ) ) ;
ret += Dfs ( S, Inf ) ;
}
return ret ;
}
} Lazer ;
int main ( ) {
scanf ( "%d%d", &n, &m ) ;
for ( int i = 1 ; i <= n ; ++ i )
for ( int j = 1 ; j <= m ; ++ j ) {
scanf ( "%d", &x ) ;
ans += x;
AddDbe ( S, P(i, j), x ) ;
}
for ( int i = 1 ; i <= n ; ++ i )
for ( int j = 1 ; j <= m ; ++ j ) {
scanf ( "%d", &x ) ;
ans += x;
AddDbe ( P(i, j), T, x ) ;
}
for ( int i = 1 ; i <= n ; ++ i )
for ( int j = 1 ; j <= m ; ++ j ) {
scanf ( "%d", &x ) ;
ans += x ;
AddDbe ( S, P(i, j) + m * n, x ) ;
for( int k = 0 ; k <= 4 ; ++ k ) {
int x = i + dx[k] ;
int y = j + dy[k] ;
if ( x <= 0 || y <= 0 || x > n || y > m ) continue ;
AddDbe (P(i, j) + m * n, P(x, y) , Inf ) ;
}
}
for ( int i = 1 ; i <= n ; ++ i )
for ( int j = 1 ; j <= m ; ++ j ) {
scanf ( "%d", &x ) ;
ans += x ;
AddDbe ( P(i, j) + ( ( m * n ) << 1 ), T, x ) ;
for( int k = 0 ; k <= 4 ; ++ k ) {
int x = i + dx[k] ;
int y = j + dy[k] ;
if ( x <= 0 || y <= 0 || x > n || y > m ) continue ;
AddDbe ( P(x, y) , P(i, j) + ( ( m * n ) << 1 ) , Inf ) ;
}
}
printf ( "%d\n", ans - Lazer.Dinic ( S, T ) ) ;
}