Loading

【题解】ABC193F - Zebraness/【笔记】项目安排问题

给定一个 \(0/1/?\) 矩阵,在 \(?\) 处填上 \(0/1\),使得相邻且异色的地方最多。

使得相邻且异色最多,等价于相邻且同色最少。矩阵建图后是二分图,所以对矩阵黑白染色后,将黑色格子上的 \(0/1\) 取反,问题转化为求相邻且异色的最少。

转化为网络流模型,对于固定为 \(0\) 的位置,连源点 \(S\),固定为 \(1\) 的点连汇点 \(T\),相邻的点连边权为 \(1\) 的无向边。这张图的最小割就是答案。

#define N 10005
int n, s, t, h[N], tot = 1, cur[N], d[N]; char u[105];
struct edge{int to, nxt, cap;}e[N << 4];
void add(int x,int y,int z){
	e[++tot].nxt = h[x], h[x] = tot, e[tot].to = y, e[tot].cap = z;
	e[++tot].nxt = h[y], h[y] = tot, e[tot].to = x, e[tot].cap = 0;
}
inline int g(int x,int y){return (x - 1) * n + y;}
queue<int>q;
bool bfs(){
	memset(d, 0, sizeof(d));
	d[s] = 1, q.push(s);
	while(!q.empty()){
		int x = q.front(); q.pop(), cur[x] = h[x];
		for(int i = h[x]; i ;i = e[i].nxt)if(e[i].cap && ! d[e[i].to])
			d[e[i].to] = d[x] + 1, q.push(e[i].to);
	}
	return d[t] ? true : false;
}
int dfs(int x,int flow){
	if(x == t)return flow;
	int res = flow;
	for(int &i = cur[x]; i; i = e[i].nxt)if(e[i].cap && d[x] + 1 == d[e[i].to]){
		int now = dfs(e[i].to, min(e[i].cap, res));
		if(!now)d[e[i].to] = 0;
		else e[i].cap -= now, e[i ^ 1].cap += now, res -= now;
		if(!res)return flow;
	}
	return flow - res;
}
int main() {
	//int T = read();while(T--)solve();
	n = read(), s = n * n + 1, t = s + 1;
	int ans = 2 * n * (n - 1);
	rp(i, n){
		scanf("%s", u + 1);
		rp(j, n)if(u[j] != '?'){
			if((u[j] == 'B') ^ ((i + j) & 1))add(s, g(i, j), inf);
			else add(g(i, j), t, inf);
		}
	}
	rp(i, n)rp(j, n - 1)add(g(i, j), g(i, j + 1), 1), add(g(i, j + 1), g(i, j), 1);
	rp(i, n - 1)rp(j, n)add(g(i, j), g(i + 1, j), 1), add(g(i + 1, j), g(i, j), 1);
	while(bfs())ans -= dfs(s, inf);
	cout << ans << endl;return 0;
}

再考虑一个同样的问题 [CSP-S 2021] 交通规划。仍然是使得相邻异色最少,但是有边权。我们只用将建图时给边加上边权即可。

归纳以下,这些问题本质都是一类问题——项目安排问题。

模型:给定 \(N\) 个物品,给每个物品标上 \(0/1\),标 \(0\) 的代价为 \(A_i\),标 \(1\) 的代价为 \(B_i\),有一些限制 \((i,j,k)\) 表示物品 \((i,j)\) 异色的代价为 \(k\),要使得总代价最小。

posted @ 2021-11-11 20:06  7KByte  阅读(90)  评论(0编辑  收藏  举报