题解:[ARC142E] Pairing Wizards
前言
建议收录于新网络流 24 题。
这个拆点是魔法吧。
思路分析
不失一般性,令 \(b_x \le b_y\),那么原限制转化为:
-
\(a_x \ge b_x\) 且 \(a_y \ge b_x\);
-
\(a_x \ge b_y\) 或 \(a_y \ge b_y\)。
对于第一条限制,我们令 \(x\) 的初始点权为 \(c_x=a_x\),让 \(c_x,c_y\) 每次和 \(b_y\) 取 \(\max\)。
那么我们实际上只剩下了第二条限制,因为这个形式是二选一,所以我们考虑最小割。
\(a_x \ge b_x\) 是好做的,对于每个点 \(x\),连边 \((s,x,b_x-c_x)\),如果这条边被割了,说明我们满足的是第一种可能;
\(a_y \ge b_x\) 的问题在于,如果有多个对 \(y\) 的限制,我们很容易算重。
然后是魔法时刻!
考虑对右部点 \(x\) 按值域拆点,\((y,v)\) 表示 \(y\) 点权为 \(c_y+v\) 的状态,对于 \(a_x \ge b_y\) 的限制,我们需要连边 \((y,(x,b_y-c_x),+\infty)\)。
对于右部点内部,连边 \(((x,v-1),(x,v),+\infty),((x,v),t,1)\)。
这样我们右部点割到了 \((x,v)\) 就表示 \(x\) 此时真正的点权为 \(c_x+v\)。
原图的最小割加上 \(\sum_{x=1}^{n} c_x-a_x\) 就是答案。
复杂度 \(O(能过)\)。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int maxn=100;
int n,m,s,t,ans,a[105],b[105],c[105],x[10005],y[10005],L[105],R[105][105],dcnt;
int head[200005],nxt[200005],targetx[200005],targetw[200005],targetf[200005],tot=1;
void add(int x,int y,int w,int f){
tot++;
nxt[tot]=head[x];
head[x]=tot;
targetx[tot]=y;
targetw[tot]=w;
targetf[tot]=f;
}
int dis[200005],now[200005];
queue<int> q;
bool bfs(){
for(int i=1;i<=dcnt;i++){
dis[i]=inf;
now[i]=head[i];
}
dis[s]=1;
q.push(s);
while(q.size()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=nxt[i]){
int y=targetx[i],w=targetw[i],f=targetf[i];
if(dis[y]!=inf || w-f==0) continue;
dis[y]=dis[x]+1;
q.push(y);
}
}
return dis[t]!=inf;
}
int dfs(int x,int sum){
if(x==t) return sum;
int res=0;
for(int i=head[x];i;i=nxt[i]){
int y=targetx[i],w=targetw[i],f=targetf[i];
if(dis[y]!=dis[x]+1 || w-f==0) continue;
int tp=dfs(y,min(sum,w-f));
if(!tp) dis[y]=inf;
else{
targetf[i]+=tp;
targetf[i^1]-=tp;
sum-=tp;
res+=tp;
}
if(!sum) break;
}
return res;
}
int dinic(){
int ans=0;
while(bfs()) ans+=dfs(s,inf);
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i];
c[i]=a[i];
}
cin>>m;
for(int i=1;i<=m;i++){
cin>>x[i]>>y[i];
if(b[x[i]]>b[y[i]]) swap(x[i],y[i]);
c[x[i]]=max(c[x[i]],b[x[i]]);
c[y[i]]=max(c[y[i]],b[x[i]]);
}
s=++dcnt;
t=++dcnt;
for(int i=1;i<=n;i++){
L[i]=++dcnt;
if(c[i]<b[i]){
add(s,L[i],b[i]-c[i],0);
add(L[i],s,0,0);
}
R[i][0]=++dcnt;
for(int j=1;j<=maxn;j++){
R[i][j]=++dcnt;
add(R[i][j],t,1,0);
add(t,R[i][j],0,0);
add(R[i][j],R[i][j-1],inf,0);
add(R[i][j-1],R[i][j],0,0);
}
}
for(int i=1;i<=m;i++){
if(c[x[i]]>=b[y[i]] || c[y[i]]>=b[y[i]]) continue;
add(L[y[i]],R[x[i]][b[y[i]]-c[x[i]]],inf,0);
add(R[x[i]][b[y[i]]-c[x[i]]],L[y[i]],0,0);
}
for(int i=1;i<=n;i++){
ans+=c[i]-a[i];
}
cout<<ans+dinic();
return 0;
}

浙公网安备 33010602011771号