题解 P4474 【王者之剑】

题目链接

二分图最大点权独立集了解一下?

题目分析

如果把题意翻译成人话,意思就是:

在网格中选择格点,如果选择了一个点,那么它周围的四个点都不能选。 求所有方案的最大值。

我只能说,都是套路了。。。

解题步骤

  • 将坐标和为偶数的格点与源点相连,奇数则为汇点相连,边权为当前点的点权;

原因:稍微观察就会发现,每个格点与他周围的四个格点的坐标和奇偶性不同,说明相同奇偶性的格点不会相互排斥,也就是可以同时选。所以将不同奇偶性连向不同端点就好了。

  • 如果坐标和为偶数(因为偶数与汇点相连),从当前点向周围四个点连边,边权为正无穷,意为连接的两个点不能同时选择。

  • 最后,就是 \(dinic\) 模板求最小割

完整代码

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define rt register int
#define int long long
const int N = 1e4 + 10, M = 1e5 + 10,inf = 2e9;
int n,m,S,T,tot = 1,head[N],cur[N],dep[N],f[M],ans;
int a[4][2] = {{-1,0},{0,-1},{0,1},{1,0}};
struct node {
	int to,nex;
}e[M];
inline void add(int x,int y,int w) {
	e[++tot] = (node) {y,head[x]}, f[tot] = w, head[x] = tot;
	e[++tot] = (node) {x,head[y]}, head[y] = tot;
}
inline void read(int &x) {
	x = 0;
	int ff = 1; char s = getchar();
	while(s < '0' || s > '9') {s = getchar();}
	while(s <= '9' && s >= '0') { x = x * 10 + s - '0'; s = getchar();}
	x *= ff;
}
inline bool bfs() {
	memset(dep,-1,sizeof(dep));
	dep[S] = 0, cur[S] = head[S];
	queue<int> q;
	q.push(S);
	int now,ver;
	while(!q.empty()) {
		now = q.front();
		q.pop();
		for(rt i = head[now]; i; i = e[i].nex) {
			ver = e[i].to;
			if(dep[ver] == -1 && f[i]) {
				dep[ver] = dep[now] + 1, cur[ver] = head[ver];
				if(ver == T) return 1;
				q.push(ver);
			}
		}
	} 
	return 0;
}
inline int find(int x,int limit) {
	if(x == T) return limit;
	int ver,flow = 0,tmp;
	for(rt i = cur[x]; i && flow < limit; i = e[i].nex) {
		cur[x] = i, ver = e[i].to;
		if(dep[ver] == dep[x] + 1 && f[i]) {
			tmp = find(ver,min(limit - flow,f[i]));
			if(!tmp) dep[ver] = -1;
			f[i] -= tmp, f[i ^ 1] += tmp, flow += tmp;
		}
	}
	return flow;
}
inline int dinic() {
	int res = 0,flow;
	while(bfs()) while(flow = find(S,inf)) res += flow;
	return res;
}
inline int pos(int x,int y) {
	return (x - 1) * m + y;
}
signed main() {
	read(n), read(m);
	S = n * m + 1,T = n * m + 2;
	int x,tx,ty;
	for(rt i = 1; i <= n; i ++) {
		for(rt j = 1; j <= m; j ++) {
			read(x);
			ans += x;
			if((i + j) & 1) add(pos(i,j),T,x);
			else {
				add(S,pos(i,j),x);
				for(rt k = 0; k < 4; k ++) {
					tx = i + a[k][0], ty = j + a[k][1];
					if(tx >= 1 && tx <= n && ty >= 1 && ty <= m) {
						add(pos(i,j),pos(tx,ty),inf);
					}
				}
			}
		}
	}
	printf("%lld",ans - dinic());
	return 0;
}
posted @ 2021-01-14 22:07  Spring-Araki  阅读(70)  评论(0)    收藏  举报