标签:lin define pre efi += memset mat i++ return
这道题题目是费用流
但实际上跟费用流没有一点关系,
我们首先思考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;
}
标签:lin define pre efi += memset mat i++ return
原文地址:https://www.cnblogs.com/loney-s/p/12031008.html