Description
Input
第一行包含二个整数N,M
接下来M行代表M条边,表示这个交通网络
每行六个整数,表示Ui,Vi,Ai,Bi,Ci,Di
接下来一行包含一条边,表示连接起点的边
Output
一个浮点数,保留二位小数。表示答案,数据保证答案大于0
Sample Input
5 10
1 5 13 13 0 412
2 5 30 18 396 148
1 5 33 31 0 39
4 5 22 4 0 786
4 5 13 32 0 561
4 5 3 48 0 460
2 5 32 47 604 258
5 7 44 37 75 164
5 7 34 50 925 441
6 2 26 38 1000 22
1 5 13 13 0 412
2 5 30 18 396 148
1 5 33 31 0 39
4 5 22 4 0 786
4 5 13 32 0 561
4 5 3 48 0 460
2 5 32 47 604 258
5 7 44 37 75 164
5 7 34 50 925 441
6 2 26 38 1000 22
Sample Output
103.00
HINT
1<=N<=5000
0<=M<=3000
1<=Ui,Vi<=N+2
0<=Ai,Bi<=500
0<=Ci<=10000
0<=Di<=1000
很久之前就想做这道题了...
上午叶大佬给我看了APIO2017 T3后,特别想找一道0/1分数规划打一打
这个题首先分数规划的思路是比较显然的...设答案为mid,wi为一次操作的贡献,n为次数;
X-Y>=mid*n;
X-(X+∑wi)>=mid*n=mid*∑1;
X-(X+∑wi+mid)>=0;
∑wi+mid<=0;
那么我们就是需要判断∑wi+mid的最小值<=0;
首先可以很好的知道缩一条边的贡献是ai-di,扩大一条边的贡献是bi+di;
但是我们必须满足流量不变且每条边满载,
然后我发现修改一条边是牵一发而动全身的,为了一条边需要修改一连串的边且要一直到起点出来的那条边.
然后就觉得很完蛋...其实好像可以用判负圈那套理论...
于是在网上看到了一种很有道理的想法.是一种基于调整的思路.
假设先把所有的道路压缩为0,那么初始费用为:∑(ai-di+mid)*ci;
然后用费用流进行调整:
对于原图中的每条边进行两种调整:
1.连容量为c,费用为-(ai-di+mid)的边;
2.连容量为Inf,费用为(bi+di+mid)的边;(从起点出发的不连)
对于第一种边表示撤回原来的压缩操作,对于第二种边表示进行扩大操作.
这样做的正确性:
1.由于是最小费用最大流所以会优先增广第一种费用小的边,所以一定是把所有压缩操作撤回了,再考虑扩大操作的
2.由于是最小费用最大流,所以新图的最大流和原图相等,流量平衡了
妙不可言
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define RG register using namespace std; const int N=100000; const int Inf=19260817; const double eps=1e-5; int head[N],nxt[N],to[N],s[N],fa[N],cnt=1,n,m,S,T,tt; int w[N],ti[N],vis[N],q[N*10]; double c[N],dis[N],cost,ans; struct data{ int u,v,a,b,c,d; }a[N]; inline void Addedge(RG int x,RG int y,RG int z,RG double v){ to[++cnt]=y,nxt[cnt]=head[x],s[cnt]=z,c[cnt]=v,head[x]=cnt; } inline void lnk(RG int x,RG int y,RG int z,RG double v){ Addedge(x,y,z,v);Addedge(y,x,0,-v); } inline bool spfa(){ for(RG int i=1;i<=T;i++) vis[i]=0,dis[i]=Inf; int t=0,sum=1;q[0]=S,vis[S]=1,dis[S]=0; while(t<sum){ int now=q[t++];vis[now]=0; for(RG int i=head[now];i;i=nxt[i]){ int y=to[i]; if(dis[y]>dis[now]+c[i]&&s[i]){ fa[y]=i;dis[y]=dis[now]+c[i]; if(!vis[y]) vis[y]=1,q[sum++]=y; } } } if(abs(dis[T]-Inf)<=eps) return 0; int f=Inf; for(RG int i=fa[T];i;i=fa[to[i^1]]) f=min(f,s[i]); for(RG int i=fa[T];i;i=fa[to[i^1]]) s[i]-=f,s[i^1]+=f; cost+=dis[T]*f; return 1; } void rebuild(double mid){ memset(head,0,sizeof(head));cnt=1; for(int i=1;i<=m;i++){ lnk(a[i].u,a[i].v,a[i].c,-(-a[i].d+a[i].a+mid)); if(a[i].u!=S) lnk(a[i].u,a[i].v,Inf,a[i].b+a[i].d+mid); } } bool check(double mid){ rebuild(mid);double ret=0;cost=0; for(int i=1;i<=m;i++){ ret+=(-a[i].d+a[i].a+mid)*a[i].c; } while(spfa()); return 0-(ret+cost)>=eps; } int main(){ scanf("%d%d",&n,&m);S=n+1,T=n+2; for(int i=1;i<=m;i++){ scanf("%d%d%d%d%d%d",&a[i].u,&a[i].v,&a[i].a,&a[i].b,&a[i].c,&a[i].d); } double l=0,r=30000.0; while(r-l>=eps){ double mid=(l+r)/2; if(check(mid)) ans=mid,l=mid; else r=mid; } printf("%.2f",ans); return 0; }