【题解】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\),要使得总代价最小。