题目大意:给出一个表格,每个人要选择文科或者理科,每个人选择文科有一个满意度,选择理科有一个满意度,以一个人为中心的五个人全选择一科也有一个满意度。问最大的满意度是多少。
思路:以后看到文理分科之类的8成应该就是最小割了。
先把答案全部累加起来,然后减去建图之后的最大流就是答案。
S->每个人 f:这个人选择文科的满意度
每个人->T f:这个人选择理科的满意度
对于每一个人多建立两个新点,分别表示以这个点为中心的五个点全部选择文科和理科。记这两个点为S1和S2。
S1->以这个点为中心的五个点 f:INF
一这个点为中心的五个点->S2 f:INF
然后就是裸的最小割了。
CODE:
#define _CRT_SECURE_NO_WARNINGS #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 1000010 #define MAXP 30010 #define INF 0x3f3f3f3f #define S 0 #define T (MAXP - 1) using namespace std; const int dx[] = {0,1,-1,0,0}; const int dy[] = {0,0,0,1,-1}; struct MaxFlow{ int head[MAXP],total; int next[MAX],aim[MAX],flow[MAX]; int deep[MAXP]; MaxFlow():total(1) {} void Add(int x,int y,int f) { next[++total] = head[x]; aim[total] = y; flow[total] = f; head[x] = total; } void Insert(int x,int y,int f) { Add(x,y,f); Add(y,x,0); } bool BFS() { static queue<int> q; while(!q.empty()) q.pop(); memset(deep,0,sizeof(deep)); deep[S] = 1; q.push(S); while(!q.empty()) { int x = q.front(); q.pop(); for(int i = head[x]; i; i = next[i]) if(flow[i] && !deep[aim[i]]) { deep[aim[i]] = deep[x] + 1; q.push(aim[i]); if(aim[i] == T) return true; } } return false; } int Dinic(int x,int f) { if(x == T) return f; int temp = f; for(int i = head[x]; i; i = next[i]) if(flow[i] && deep[aim[i]] == deep[x] + 1 && temp) { int away = Dinic(aim[i],min(temp,flow[i])); if(!away) deep[aim[i]] = 0; flow[i] -= away; flow[i^1] += away; temp -= away; } return f - temp; } }solver; int m,n; int InA[MAX],OutA[MAX]; int num[110][110],cnt; int main() { cin >> m >> n; for(int i = 1; i <= m; ++i) for(int j = 1; j <= n; ++j) num[i][j] = ++cnt; int ans = 0; for(int i = 1; i <= m; ++i) for(int x,j = 1; j <= n; ++j) { scanf("%d",&x); ans += x; solver.Insert(S,num[i][j] * 3,x); } for(int i = 1; i <= m; ++i) for(int x,j = 1; j <= n; ++j) { scanf("%d",&x); ans += x; solver.Insert(num[i][j] * 3,T,x); } for(int i = 1; i <= m; ++i) for(int x,j = 1; j <= n; ++j) { scanf("%d",&x); ans += x; solver.Insert(S,num[i][j] * 3 + 1,x); for(int k = 0; k <= 4; ++k) { int fx = i + dx[k],fy = j + dy[k]; if(!fx || !fy || fx > m || fy > n) continue; solver.Insert(num[i][j] * 3 + 1,num[fx][fy] * 3,INF); } } for(int i = 1; i <= m; ++i) for(int x,j = 1; j <= n; ++j) { scanf("%d",&x); ans += x; solver.Insert(num[i][j] * 3 + 2,T,x); for(int k = 0; k <= 4; ++k) { int fx = i + dx[k],fy = j + dy[k]; if(!fx || !fy || fx > m || fy > n) continue; solver.Insert(num[fx][fy] * 3,num[i][j] * 3 + 2,INF); } } int max_flow = 0; while(solver.BFS()) max_flow += solver.Dinic(S,INF); cout << ans - max_flow << endl; return 0; }