BZOJ3597: [Scoi2014]方伯伯运椰子
输入格式:
第1 行包含2 个整数n,m接下来m 行代表m 条边,表示这个交通网络。
每行6 个整数,表示ui,vi,ai,bi,ci,di.
接下来1 行包含1 条边,表示连接起点的边
输出格式:
一个浮点数,保留2 位小数,表示要求的答案,数据保证答案大于0样例输入:
6 7 1 2 0 0 1 1000 2 4 0 0 1 1000 4 6 0 0 1 1000 1 3 0 0 0 0 3 5 0 0 0 0 5 6 0 0 0 0 6 8 0 0 1 0 7 1 0 0 1 0
样例输出:
500.00
数据范围:
时间限制:
3s空间限制:
64M具体思路:要求的答案好奇怪啊,好像很像分数规划啊
那么就用分数规划做吧
根据套路,我们要二分一下答案
然后怎么办办勒
发现由于原图是满流的,所以最优方案一定是从一个点到另一个点的一条路径+1流量,另一条-1流量
那么对于流量>0的边,可以加流量,那就连一条长为单位流量+加流量需要的代价,也可以减流量那就连一条长为-单位流量+减流量需要的代价的反向边
对于流量为0的边,就只可以加流量了
然后把每个边的长+mid(二分的答案)然后SPFA判一下有无负环就好了
AC代码:
#include<bits/stdc++.h> #define INF 100000000 const double eps=1e-6; using namespace std; int x,y,n,m,i,j,top=1,A,B,C,D,first[200000],next[200000],last[200000],to[200000]; int bo[200000]; double dis[200000],len[200000],ans; void add(int x,int y,int l) { top++,to[top]=y,len[top]=(double)l; if(first[x]==0)first[x]=top;else next[last[x]]=top; last[x]=top; } void SPFA(int x,double mid) { if(ans)return; bo[x]=true; for(int i=first[x];i;i=next[i]) if(dis[x]+len[i]+mid<dis[to[i]]) { if(bo[to[i]]||ans) { ans=1; break; } dis[to[i]]=dis[x]+len[i]+mid; SPFA(to[i],mid); } if(ans)return; bo[x]=false; } bool ok(double mid) { for(int i=1;i<=n+2;i++)dis[i]=0.0,bo[i]=0; for(int i=1;i<=n+2;i++) { ans=0;SPFA(i,mid); if(ans)return true; } return false; } int main() { scanf("%d%d",&n,&m); for(i=1;i<=m+1;i++) { scanf("%d%d%d%d%d%d",&x,&y,&A,&B,&C,&D); if(C)add(x,y,D+B),add(y,x,A-D);else add(x,y,B+D); } double l=0,r=1000.0,mid; while(r-l>eps) { mid=(l+r)/2.0; if(ok(mid))l=mid;else r=mid; } printf("%.2lf",mid); }