当 x i x_i xi 取值等于 a i a_i ai 时不产生代价,否则产生 1 1 1 的代价
有 m m m 个二元组 ( i , j ) (i,j) (i,j)
表示 ( i , j ) (i,j) (i,j) 取值不同则会产生 1 1 1 的代价
求最小代价和
2 ≤ n ≤ 300 2\le n\le300 2≤n≤300
做法
源点 S S S 汇点 T T T
对于所有的 1 ≤ i ≤ n 1\le i\le n 1≤i≤n ,对第 i i i 个变量 x i x_i xi 建点 i i i
如果 a i = 0 a_i=0 ai=0
则由 S S S 向 i i i 连容量为 1 1 1 的边
由 i i i 向 T T T 连容量为 0 0 0 的边
否则由 S S S 向 i i i 连容量为 0 0 0 的边
i i i 向 T T T 连容量为 1 1 1 的边
这时候边 < S , i > <S,i> <S,i> 和 < i , T > <i,T> <i,T> 显然有且仅有一条边被割掉
可以看成如果保留边 < S , i > <S,i> <S,i> 则 x i x_i xi 取 0 0 0
否则 x i x_i xi 取 1 1 1
考虑处理变量间的影响
对于二元组 ( i , j ) (i,j) (i,j) ,连边 < i , j > <i,j> <i,j> 和 < j , i > <j,i> <j,i> ,容量都为 1 1 1
这样的含义是,如果保留了边 < S , i > <S,i> <S,i> 和 边 < j , T > <j,T> <j,T> ,那么还需要额外割掉边 < i , j > <i,j> <i,j> ,否则存在一条 S S S 到 T T T 的路径 S − > i − > j − > T S->i->j->T S−>i−>j−>T
< j , i > <j,i> <j,i> 同理
实际上容量为 0 0 0 的边没必要建,在上面只是为了便于理解而建出来
求一遍最小割即为答案
此外,如果二元组 ( i , j ) (i,j) (i,j) 是限制 x i x_i xi 必须等于 x j x_j xj ,则只需要把 < i , j > <i,j> <i,j> 和 < j , i > <j,i> <j,i> 的容量设为 ∞ \infty ∞ (表示该边割不掉)即可
代码
#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define For(i, a, b) for (i = a; i <= b; i++)#define Edge(u) for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])#define NF(u) for (int &e = cur[u], v = go[e]; e; e = nxt[e], v = go[e])inlineintread(){
int res =0;bool bo =0;char c;while(((c =getchar())<'0'|| c >'9')&& c !='-');if(c =='-') bo =1;else res = c -48;while((c =getchar())>='0'&& c <='9')
res =(res <<3)+(res <<1)+(c -48);return bo ?~res +1: res;}template<classT>inline T Min(const T &a,const T &b){
return a < b ? a : b;}constint N =610, M =6e5+5, INF =0x3f3f3f3f;int n, m, ecnt =1, nxt[M], adj[N], go[M], cap[M], S, T, lev[N],
len, que[N], cur[N], ans;voidadd_edge(int u,int v,int w){
nxt[++ecnt]= adj[u]; adj[u]= ecnt; go[ecnt]= v; cap[ecnt]= w;
nxt[++ecnt]= adj[v]; adj[v]= ecnt; go[ecnt]= u; cap[ecnt]=0;}boolbfs(){
int i;
For (i, S, T) cur[i]= adj[i], lev[i]=-1;
lev[que[len =1]= S]=0;
For (i,1, len){
int u = que[i];Edge(u)if(cap[e]&& lev[v]==-1){
lev[que[++len]= v]= lev[u]+1;if(v == T)return1;}}return0;}intdinic(int u,int flow){
if(u == T)return flow;int res =0, delta;NF(u)if(cap[e]&& lev[u]< lev[v]){
delta =dinic(v,Min(cap[e], flow - res));if(delta){
cap[e]-= delta; cap[e ^1]+= delta;
res += delta;if(res == flow)break;}}if(res != flow) lev[u]=-1;return res;}intmain(){
int i, x, y;
n =read(); m =read();
S =1; T = n +2;
For (i,1, n){
x =read();if(x)add_edge(1+ i, T,1);elseadd_edge(S,1+ i,1);}while(m--) x =read(), y =read(),add_edge(x +1, y +1,1),add_edge(y +1, x +1,1);while(bfs()) ans +=dinic(S, INF);
std::cout << ans << std::endl;return0;}
对于任意的 1 ≤ i ≤ n , 1 ≤ j ≤ m 1\le i\le n,1\le j\le m 1≤i≤n,1≤j≤m
如果 x i , j = 0 x_{i,j}=0 xi,j=0 则有 a i , j a_{i,j} ai,j 的收益
如果 x i , j = 1 x_{i,j}=1 xi,j=1 则有 b i , j b_{i,j} bi,j 的收益
对于每个相邻(有且仅有一条公共边)的格子 ( i , j ) (i,j) (i,j) ( u , v ) (u,v) (u,v)
如果 x i , j = x u , v = 0 x_{i,j}=x_{u,v}=0 xi,j=xu,v=0 则有 c i , j , u , v c_{i,j,u,v} ci,j,u,v 的收益
如果 x i , j = x u , v = 1 x_{i,j}=x_{u,v}=1 xi,j=xu,v=1 则有 d i , j , u , v d_{i,j,u,v} di,j,u,v 的收益
n , m ≤ 100 n,m\le 100 n,m≤100 , 0 ≤ a i , j , b i , j , c i , j , u , v , d i , j , u , v ≤ 5000 0\le a_{i,j},b_{i,j},c_{i,j,u,v},d_{i,j,u,v}\le 5000 0≤ai,j,bi,j,ci,j,u,v,di,j,u,v≤5000
做法
转化问题
如果 x i , j = 0 x_{i,j}=0 xi,j=0 则有 b i , j b_{i,j} bi,j 的代价
如果 x i , j = 1 x_{i,j}=1 xi,j=1 则有 a i , j a_{i,j} ai,j 的代价
对于每个相邻(有且仅有一条公共边)的格子 ( i , j ) (i,j) (i,j) ( u , v ) (u,v) (u,v)
如果 ( i , j ) = 0 (i,j)=0 (i,j)=0 或 ( u , v ) = 0 (u,v)=0 (u,v)=0 则有 d i , j , u , v d_{i,j,u,v} di,j,u,v 的代价
如果 ( i , j ) = 1 (i,j)=1 (i,j)=1 或 ( u , v ) = 1 (u,v)=1 (u,v)=1 则有 c i , j , u , v c_{i,j,u,v} ci,j,u,v 的代价
求
∑ a + ∑ b + ∑ c + ∑ d − 最 小 代 价 和 \sum a+\sum b+\sum c+\sum d-最小代价和 ∑a+∑b+∑c+∑d−最小代价和
发现与上一题不同的地方就在于 c 和 d 不相等
所以我们考虑设
p i , j = a i , j + ∑ i ≤ u , j ≤ v c i , j , u , v p_{i,j}=a_{i,j}+\sum_{i\le u,j\le v}c_{i,j,u,v} pi,j=ai,j+i≤u,j≤v∑ci,j,u,v
q i , j = b i , j + ∑ i ≤ u , j ≤ v d i , j , u , v q_{i,j}=b_{i,j}+\sum_{i\le u,j\le v}d_{i,j,u,v} qi,j=bi,j+i≤u,j≤v∑di,j,u,v
由 S S S 向点 ( i , j ) (i,j) (i,j) 连容量为 p i , j p_{i,j} pi,j 的边
点 ( i , j ) (i,j) (i,j) 向 T T T 连容量为 q i , j q_{i,j} qi,j 的边
对于每个 ( i , j , u , v ) (i,j,u,v) (i,j,u,v) ( i ≤ u , j ≤ v i\le u,j\le v i≤u,j≤v )
由点 ( i , j ) (i,j) (i,j) 向点 ( u , v ) (u,v) (u,v) 连容量为 c i , j , u , v c_{i,j,u,v} ci,j,u,v 的边