题解:P14122 [SCCPC 2021] Direction Setting
题目大意
挺简单的一道费用流题目,给定
有最小值(
解题思路
贪心的思路来想,我们要求得
由于先前的想法,我们可以将这一个点
而对于源点
但是我们不难发现,这道题竟然还有第二问,但是这会比刚刚的建模要来得简单,按照上面的说法,若有一条边的其中一个点被增广了,那么
代码如下
#include<bits/stdc++.h>
using namespace std;
int T,n,m,ans,ansc,s,t;
int jl[100005],cur[100005],pd[100005],dl[100005],cc[4000][2],ii;
struct sbb {
int a,b,rl,bq;
};
vector<sbb>bian;
vector<int>qu[100005];
void add(int a,int b,int c,int d) {
bian.push_back({a,b,c,d});
bian.push_back({b,a,0,-d});
int sz=bian.size();
if(c==1&&d==0&&a!=s&&a!=t&&b!=s&&b!=t)cc[ii][0]=sz-2,cc[ii][1]=sz-1;
qu[a].push_back(sz-2);
qu[b].push_back(sz-1);
return ;
}
int spfa() {
for(int i=s; i<=t; i++)jl[i]=1e9,pd[i]=cur[i]=0;
dl[0]=1,dl[1]=s,jl[s]=0;
int f=0;
while(f<dl[0]) {
int wz=dl[++f];
pd[wz]=0;
for(auto I:qu[wz]) {
int nwz=bian[I].b;
if(jl[nwz]<=jl[wz]+bian[I].bq||bian[I].rl<=0)continue;
jl[nwz]=jl[wz]+bian[I].bq;
if(pd[nwz]==0)pd[nwz]=1,dl[++dl[0]]=nwz;
}
}
return (jl[t]!=1e9);
}
int dfs(int wz,int mq) {
if(wz==t)return mq;
pd[wz]=1;
int nans=0;
for(int &I=cur[wz]; I<qu[wz].size(); I++) {
int i=qu[wz][I];
int nwz=bian[i].b,z;
if(jl[nwz]!=jl[wz]+bian[i].bq||pd[nwz]==1||bian[i].rl<=0)continue;
z=dfs(nwz,min(mq,bian[i].rl));
ansc+=z*bian[i].bq,nans+=z,mq-=z,bian[i].rl-=z,bian[(i^1)].rl+=z;
if(mq<=0)break;
}
pd[wz]=0;
return nans;
}
int dn() {
ans=0,ansc=0;
while(spfa()==1)ans+=dfs(s,1e9);
return ans;
}
int a[100005],x[4000],y[4000];
void chuli() {
bian.clear();//多测记得清空
for(int i=0; i<=3050; i++)qu[i].clear();
cin>>n>>m;
s=0,t=n+m+10;
for(int i=1; i<=n; i++)cin>>a[i];
for(int j=1; j<=m; j++) {
ii=j;
cin>>x[j]>>y[j];
add(s,j,1,0);
add(j,x[j]+m,1,0),add(j,y[j]+m,1,0);
}
for(int i=1; i<=n; i++)add(i+m,t,a[i],0),add(i+m,t,1e9,1);
dn();
cout<<ansc<<'\n';
for(int i=1; i<=m; i++)cout<<(bian[cc[i][0]].rl!=0);
cout<<'\n';
return ;
}
int main() {
cin>>T;
while(T--)chuli();
return 0;
}
小提示
- 本题有多测,所以记得要清空;
- 本题有
Special Judge,样例中的第一个的第二小问输出全是1 是正确的(虽然好像没什么用)。