习题:费用流(网络流)

题目

传送门

思路

这道题题目是费用流

但实际上跟费用流没有一点关系,

我们首先思考Bob的最优策略,

对于Bob来说

\(ans=\sum_{i=1}^{m} w_i*flow_i\)

我们发现对于Bob,

最优策略一定是将所有的单位花费全都怼在流量最大的一条边上

知道了Bob的最优策略之后,

对于Alice而言,就是将流量最大的一条边的流量尽可能小,

同时保证最大流不变

很明显,此方式是有单调性的

所以我们可以考虑二分

将二分的mid用来限制每一条边的最大容量

之后再跑最大流来检验就行了

代码

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
using namespace std;
const double eps=1e-9;
struct node
{
	int u,v;
	double w;
};
int n,m;
double p;
double l,r,mid;
double max_f;
vector<node>v;
struct networt_flow_isap
{
	#define MAXN 205
	double c[MAXN][MAXN];
	int d[MAXN];
	int vd[MAXN];
	double maxx;
	int s,t;
	vector<int> g[MAXN];
	#undef MAXN
	void add(int u,int v,double w)
	{
		g[u].push_back(v);
		g[v].push_back(u);
	}
	void init()
	{
		maxx=0;
		memset(c,0,sizeof(c));	
		memset(d,0,sizeof(d));
		memset(vd,0,sizeof(vd));
		for(int i=1;i<=n;i++)
			g[i].clear();

	}
	double dfs(int u,double f)
	{
		if(u==t)
			return f;
		double minn=0,summ=0;
		int id=n-1;
		for(int i=0;i<g[u].size();i++)
		{
			int v=g[u][i];
			if(c[u][v]>0)
			{
				if(d[u]==d[v]+1)
				{
					minn=min(f-summ,c[u][v]);
					minn=dfs(v,minn);
					c[u][v]-=minn;
					c[v][u]+=minn;
					summ+=minn;
					if(d[s]>=n)
						return summ;
					if(summ==f)
						break;
				}
				if(d[v]<id)
					id=d[v];
			}
		}
		if(summ==0)
		{
			vd[d[u]]--;
			if(!vd[d[u]])
				d[s]=n;
			d[u]=id+1;
			vd[d[u]]++;
		}
			
		return summ;
	}
	double isap(int S,int T)
	{
		memset(d,0,sizeof(d));
		memset(vd,0,sizeof(vd));
		s=S;
		t=T;
		vd[0]=n;
		maxx=0;
		while(d[s]<n)
			maxx+=dfs(s,(1ll<<60)/2);
		return maxx;
	}
}g;
void init(double cnt)
{
	memset(g.c,0,sizeof(g.c));
	for(int i=0;i<v.size();i++)
	{
		g.c[v[i].u][v[i].v]+=min(v[i].w,cnt);
		g.c[v[i].v][v[i].u]=0;
	}
}
double f_abs(double x)
{
	if(x<0)
		return -x;
	return x;
}
bool check(double cnt)
{
	init(cnt);
	double ans=g.isap(1,n);
	//cout<<cnt<<' '<<ans<<'\n';
	if(f_abs(ans-max_f)<eps)
		return 1;
	return 0;
}
int main()
{
	cin>>n>>m>>p;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		double z;
		cin>>x>>y>>z;
		v.push_back((node){x,y,z});
		g.add(x,y,z);
	}
	init(1e9);
	max_f=g.isap(1,n);
	cout<<max_f<<'\n';
	l=0;
	r=1e9;
	while(l+eps<r)
	{
		mid=(l+r)/2;
		if(check(mid))
			r=mid;
		else
			l=mid;
	}
	printf("%.5lf",mid*p);
	return 0;
}
posted @ 2019-12-12 18:50  loney_s  阅读(182)  评论(0)    收藏  举报