题目大意:Alice来弄一条最大流,Bob来给Alice弄好的最大流定权值。
定权值的方法是给没条边定一个值wi,然后wi*flow(i)的和就是总的费用,但要求所有wi之和为p。
现在Bob希望最后的费用最大,即对于每一种最大流方案都会有一种最大的定值方案。
Alice则希望花费最小,即选出一种最大流方案,使得这种方案的最大定值是所有最大流方案中最小的
求最大流,及这个最小的最大定值
题解:第一问裸流,对于第二问,Bob显然把单位费用全部放在流量最大的边上,这样Alice需要选择方案,使得在最大流的前提下流量最大的边尽量小,这个明显单调……,二分mid,将所有边权改为mid,若最大流不减少说明可行
没有保证答案为整数,所以需要实数二分……
这里为了避免实数二分把值都乘以10000
我的收获:忽视题目胡扯……题目似乎扯到了博弈论……避免实数技巧
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M=105;
#define INF 1e17
#define B 10000
int n,m,st,ed,t,p;
int head[M],last[M],d[M],num[M];
long long F,ret,mx,z[1005];
bool Exit;
struct edge{int to,nex,id;long long c;}e[2005];
void add(int u,int v,int I,long long w){e[t].id=I,e[t].to=v,e[t].nex=head[u],e[t].c=w,last[u]=head[u]=t++;}
void insert(int x,int y,int I,long long z){add(x,y,I,z),add(y,x,I,0);};
long long dfs(int x,long long in)
{
if(x==ed) return in;
long long ans=0,f;
for(int i=last[x];i!=-1;last[x]=i=e[i].nex)
{
int v=e[i].to;
if(e[i].c&&d[v]==d[x]-1){
f=dfs(v,min(in-ans,e[i].c));
ans+=f;e[i].c-=f,e[i^1].c+=f;
if(Exit||ans==in) return ans;
}
}
if(--num[d[x]]==0) Exit=1;
d[x]++,num[d[x]]++,last[x]=head[x];
return ans;
}
long long ISAP()
{
Exit=0;long long flow=0;
while(!Exit) flow+=dfs(st,INF);
return flow;
}
void build(long long x){
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));num[0]=n+1;
for(int i=0;i<t;i+=2) e[i].c=min(x,z[e[i].id]);
}
void work()
{
F=ISAP();
printf("%lld\n",F/B);
for(long long l=0,r=mx*B;l<=r;){
long long mid=l+r>>1;
build(mid);
if(ISAP()>=F) r=mid-1,ret=mid;
else l=mid+1;
}
printf("%.4lf\n",double(ret)*p/B);
}
void init()
{
cin>>n>>m>>p;
st=1,ed=n,num[0]=ed+1;
memset(head,-1,sizeof(head));
memset(last,-1,sizeof(last));
int x,y;
for(int i=1;i<=m;i++)
scanf("%d%d%lld",&x,&y,&z[i]),z[i]*=B,insert(x,y,i,z[i]),mx=max(mx,z[i]);
}
int main()
{
init();
work();
return 0;
}