题解:P3305 [SDOI2013] 费用流
wangxx2012 · · 题解
题意
就是普通网络流,然后要在网络流的几条边上加一个费用(所有边的费用加起来等于
看起来是不是很像费用流。
思路
其实这题跟费用流喵关系没有。
当看到 Bob 希望总费用尽量大时,你可能想问,每条边赋的费用有那么多种情况,总不可能一一枚举吧。
其实这里可以采用贪心的思想。我们注意到网络流上每条路径中的各个边的实际流量一致,那么为了使得费用最大,我们肯定要把实际流量最大的路径的费用设为
为什么要这样做呢?一个不太严谨但显然的证明如下:
如果你把实际流量最大的路径的费用设为
而如果你要赋其他路径,那费用就是:
但你这除了
所以这样的总费用就是最大的。
求最大?那自然而然的想到了二分。
注意到流量最大值可能不是整数,于是使用实数二分。
记得每次跑完网络流后要重新建图。
代码
主要的思路上面已经讲过,代码中就不多加赘述。
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int maxn=1e5+10;
const double inf=1e18;
const double eps=1e-6;
int n,m,s,t;
double p,maxm=-inf,ans;
int u[maxn],v[maxn];
double w[maxn];
struct node{
int to,next;
double w;
}e[2*maxn];
int head[maxn],tot=1;
void add(int u,int v,double w){
e[++tot].to=v;
e[tot].next=head[u];
e[tot].w=w;
head[u]=tot;
}
int dep[maxn],cur[maxn];
bool bfs(){
queue<int> q;
memset(dep,-1,sizeof(dep));
dep[s]=0; q.push(s);
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(dep[v]==-1&&e[i].w>eps){
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[t]!=-1;
}
double dfs(int u,double flow){
if(u==t) return flow;
double used=0;
for(int i=cur[u];i;i=e[i].next){
cur[u]=i;
int v=e[i].to;
if(dep[v]==dep[u]+1&&e[i].w>eps){
double rlow=dfs(v,min(flow-used,e[i].w));
if(rlow>eps){
e[i].w-=rlow; e[i^1].w+=rlow;
used+=rlow;
if(fabs(flow-used)<eps) break;
}
}
}
return used;
}
double dinic(){
double ans=0;
while(bfs()){
memcpy(cur,head,sizeof(cur));
ans+=dfs(s,inf);
}
return ans;
}
void reset(double x){
memset(head,0,sizeof(head)); tot=1;
for(int i=1;i<=m;i++){
double cap=min(x,w[i]);
add(u[i],v[i],cap),add(v[i],u[i],0);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m>>p; s=1,t=n;
for(int i=1;i<=m;i++){
cin>>u[i]>>v[i]>>w[i];
add(u[i],v[i],w[i]); add(v[i],u[i],0);
maxm=max(maxm,w[i]);
}
double l=0,r=maxm,ans=r;
double f=dinic();
while(r-l>eps){
double mid=(l+r)/2;
reset(mid);
if(dinic()>=f-eps){
ans=mid;
r=mid;
}
else l=mid;
}
printf("%.0lf\n%.4lf",f,ans*p);
return 0;
}
总结
此题唯一难点在于二分,甚至说建图都是模版式建图。
建议降蓝。
觉得自己二分不好的可以做完此题后,再做做 这道题。