# [BZOJ 2127] Happiness

[题目链接]

[算法]

首先默认每个人都选文科

那么 ， "选"就是指选理科 ， 而"不选"就是指选文科

那么选所获得的收益就是(V理 - V文)

而额外获得的收益可以看作是 : 若两个点同时选 ， 可以获得一些收益和若两个点中有一个不选 ， 则会失去收益

解最大权闭合子图 ， 即可

时间复杂度 : O(dinic(N,M))

[代码]

#include<bits/stdc++.h>
using namespace std;
#define N 110
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int inf = 2e9;

struct edge
{
int to , w , nxt;
} e[N * N * 50];

int total , tot , S , T , n , m;
int head[N * N * 5] , dep[N * N * 5] , a[N][N] , b[N][N] , point[N][N];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
T f = 1; x = 0;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
x *= f;
}
inline void addedge(int u , int v , int w)
{
++tot;
e[tot] = (edge){v , w , head[u]};
head[u] = tot;
++tot;
e[tot] = (edge){u , 0 , head[v]};
head[v] = tot;
}
inline bool bfs()
{
queue< int > q;
for (int i = 1; i <= total; i++) dep[i] = -1;
dep[T] = -1;
q.push(S);
dep[S] = 1;
while (!q.empty())
{
int cur = q.front();
q.pop();
for (int i = head[cur]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (w > 0 && dep[v] == -1)
{
dep[v] = dep[cur] + 1;
q.push(v);
if (v == T) return true;
}
}
}
return false;
}
inline int dinic(int u , int flow)
{
int rest = flow;
if (u == T)
return flow;
for (int i = head[u]; i && rest; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (w > 0 && dep[v] == dep[u] + 1)
{
int k = dinic(v , min(rest , w));
if (!k) dep[v] = 0;
rest -= k;
e[i].w -= k;
e[i ^ 1].w += k;
}
}
return flow - rest;
}

int main()
{

read(n); read(m);
int ans = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
read(a[i][j]);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
read(b[i][j]);
ans += b[i][j];
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
point[i][j] = ++total;
}
}
tot = 1;
S = 0 , T = 5 * N * N - 1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (a[i][j] >= b[i][j])
{
ans += a[i][j] - b[i][j];
addedge(S , point[i][j] , a[i][j] - b[i][j]);
} else addedge(point[i][j] , T  , b[i][j] - a[i][j]);
}
}
// NM + 4NM = 5NM
// 24NM + 2NM = 26NM
for (int i = 1; i < n; i++)
{
for (int j = 1; j <= m; j++)
{
int x;
read(x);
ans += x;
++total;
addedge(S , total , x);
addedge(total , point[i][j] , inf);
addedge(total , point[i + 1][j] , inf);
}
}
for (int i = 1; i < n; i++)
{
for (int j = 1; j <= m; j++)
{
int x;
read(x);
ans += x;
++total;
addedge(total , T , x);
addedge(point[i][j] , total , inf);
addedge(point[i + 1][j] , total , inf);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j < m; j++)
{
int x;
read(x);
ans += x;
++total;
addedge(S , total , x);
addedge(total , point[i][j] , inf);
addedge(total , point[i][j + 1] , inf);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j < m; j++)
{
int x;
read(x);
ans += x;
++total;
addedge(total , T , x);
addedge(point[i][j] , total , inf);
addedge(point[i][j + 1] , total , inf);
}
}
while (bfs())
{
while (int flow = dinic(S , inf)) ans -= flow;
}
printf("%d\n" , ans);

return 0;

}

posted @ 2019-02-10 21:19  evenbao  阅读(179)  评论(0编辑  收藏  举报