这个就是一个求最大权独立集,以为这个图是一个二分图,所以可以转换成求对偶问题,也就是最小割。
那么answer = ∑val[i][j] - 最小割。
/***************************************** Author :Crazy_AC(JamesQi) Time :2016 File Name : *****************************************/ // #pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <algorithm> #include <iomanip> #include <sstream> #include <string> #include <stack> #include <queue> #include <deque> #include <vector> #include <map> #include <set> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <climits> using namespace std; #define MEM(x,y) memset(x, y,sizeof x) #define pk push_back typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> ii; typedef pair<ii,int> iii; const double eps = 1e-10; const int inf = 1 << 30; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; int n; int val[21][21]; int dis[21*21]; struct Edge { int from, to, cap, flow, nxt; Edge(){} Edge(int from, int to,int cap, int flow,int nxt) : from(from), to(to),cap(cap), flow(flow), nxt(nxt) {} }edges[10010]; int head[21*21]; int ecnt; int dx[] = {-1, 0, 1, 0}; int dy[] = {0, -1, 0, 1}; int s, t; bool spfa(int s,int t) { queue<int> que; memset(dis, -1,sizeof dis); dis[s] = 0; que.push(s); while(!que.empty()) { int u = que.front(); que.pop(); for (int i = head[u];~i;i = edges[i].nxt) { Edge& e = edges[i]; if (e.cap > e.flow && dis[e.to] == -1) { dis[e.to] = dis[u] + 1; que.push(e.to); } } } return dis[t] != -1; } int dfs(int u,int a) { if (u == t || a == 0) return a; int flow = 0, f; for (int i = head[u];~i;i = edges[i].nxt) { Edge& e = edges[i]; if (dis[e.to] == dis[u] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) { flow += f; a -= f; e.flow += f; edges[i^1].flow -= f; if (a <= 0) break; } } if (flow == 0) dis[u] = 0; return flow; } int dinic(int s,int t) { int ret = 0; while(spfa(s, t)) { ret += dfs(s, INF); } return ret; } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); while(~scanf("%d",&n)) { int sum = 0; for (int i = 1;i <= n;++i) for (int j = 1;j <= n;++j) { scanf("%d",&val[i][j]); sum += val[i][j]; } memset(head, -1,sizeof head); ecnt = 0; s = 0,t = n*n + 1; for (int i = 1;i <= n;++i) { for (int j = 1;j <= n;++j) { if (val[i][j] >= 0) { int u = (i-1)*n+j; // printf("u = %d: ", u); edges[ecnt] = Edge(s, u, val[i][j], 0, head[s]), head[s] = ecnt++; edges[ecnt] = Edge(u, s, 0, 0, head[u]), head[u] = ecnt++; // val[i][j] = -1;// for (int k = 0;k < 4;++k) { int nx = i + dx[k]; int ny = j + dy[k]; if (nx < 1 || nx > n || ny < 1 || ny > n) continue; // printf("%d ", v); int v = (nx - 1)*n+ny; // printf("%d ", v); edges[ecnt] = Edge(v, t, val[nx][ny], 0,head[v]), head[v] = ecnt++; edges[ecnt] = Edge(t, v, 0, 0, head[t]), head[t] = ecnt++; edges[ecnt] = Edge(u, v, INF, 0,head[u]), head[u] = ecnt++; edges[ecnt] = Edge(v, u, 0, 0, head[v]), head[v] = ecnt++; val[nx][ny] = -1;// } // printf("\n"); } } } int ans = sum - dinic(s, t); // cout << sum << endl; cout << ans << endl; } return 0; }