二分图最小点覆盖和最大独立集都可以转化为最大匹配求解。
在这个基础上,把每个点赋予一个非负的权值,这两个问题就转化为:二分图最小点权覆盖和二分图最大点权独立集。
将格子染色成二分图,显然是求二分图的最大点权独立集。将问题转化为二分图最小点权覆盖来求解,最终结果=总权和-最大流。
另外: 这个dinic最大流这么写最好写。
const int inf = 0x7fffffff ; const int maxn = 20000 , maxm = 500000 ; struct Edge{ int v , f ,next ; Edge(){} Edge(int _v , int _f , int _next):v(_v) ,f(_f),next(_next){} }; int sourse , meet ; int id ; Edge e[maxm*2 + 10] ; int g[maxn + 10] ; void add(int u , int v , int f){ e[++id] = Edge(v , f ,g[u]) ; g[u] = id ; e[++id] = Edge(u , 0 , g[v]) ; g[v] = id ; } queue <int> que ; bool vis[maxn + 10] ; int dist[maxn + 10] ; void bfs(){ memset(dist , 0 , sizeof(dist)) ; while(! que.empty()) que.pop() ; que.push(sourse) ; vis[sourse] = 1 ; while(! que.empty()){ int u = que.front() ; que.pop() ; for(int i = g[u] ; i ; i = e[i].next){ int v = e[i].v ; if(e[i].f && !vis[v]){ que.push(v) ; dist[v] = dist[u] + 1 ; vis[v] = 1 ; } } } } int dfs(int u , int delta){ if(u == meet) return delta ; int ans = 0 ; for(int i = g[u] ; i && delta ; i = e[i].next){ int v = e[i].v ; if(e[i].f && dist[v] == dist[u] + 1){ int d = dfs(v , min(delta , e[i].f)) ; e[i].f -= d ; e[i^1].f += d ; delta -= d ; ans += d ; } } return ans ; } int maxflow(){ int ans = 0 ; while(1){ memset(vis , 0 , sizeof(vis)) ; bfs() ; if(! vis[meet]) return ans ; ans += dfs(sourse , inf) ; } } void init(){ memset(g , 0 , sizeof(g)) ; id = 1 ; } int main(){ int n , m , i , j , u , v , c , sum ; while(scanf("%d%d" ,&n ,&m) != EOF){ init() ; sum = 0 ; sourse = 0 ; meet = n*m + 1 ; for(i = 1 ; i <= n ; i++){ for(j = 1 ; j <= m ; j++){ scanf("%d" ,&c) ; sum += c ; u = (i-1) * m + j ; if((i+j)&1) add(u , meet , c) ; else{ add(sourse , u , c) ; if(i > 1) add(u , u-m , inf) ; if(i < n) add(u , u+m , inf) ; if(j > 1) add(u , u-1 , inf) ; if(j < m) add(u , u+1 , inf) ; } } } printf("%d\n" , sum - maxflow()) ; } return 0 ; }