标签:
前段时间准备省选没更,后段(?)时间省选考砸没心情更,最近终于开始恢复刷题了。。。
题目大意:有n个点m条有向边的图,边上有花费,点上有收益,点可以多次经过,但是收益不叠加,边也可以多次经过,但是费用叠加。求一个环使得收益和/花费和最大,输出这个比值。
显然这就是经典的分数规划题啊,就是最优比率环,那么就二分答案,将所有边(u,v)的边权改为【v的点权-(u,v)原边权*mid】,这可以算是最优比率环的公式了吧,然后判一下是否有正环,有的话就说明答案可行。判正环有够别扭的,那就全部改成相反数然后判负环吧233333
代码如下:
type point=^rec; rec=record data:longint; sum:extended; next:point; end; var n,m,x,y,z,i:longint; k:point; l,r,mid:extended; dist:array[0..1000]of extended; h:array[0..10000000]of longint; fun,num:array[0..1000]of longint; v:array[0..1000]of boolean; map:array[0..1000]of point; function spfa(x:longint):boolean; var front,rear,now,j:longint; sum:extended; i:point; begin for j:=1 to n do dist[j]:=maxlongint; dist[x]:=0;front:=0;rear:=1;h[1]:=x;v[x]:=true; while front<rear do begin inc(front); now:=h[front]; i:=map[now]; while i<>nil do begin sum:=i^.sum*mid-fun[i^.data]; if dist[i^.data]>dist[now]+sum then begin dist[i^.data]:=dist[now]+sum; if not v[i^.data] then begin if num[i^.data]>233 then exit(true); inc(rear); inc(num[i^.data]); h[rear]:=i^.data; v[i^.data]:=true; end; end; i:=i^.next; end; v[now]:=false; end; exit(false); end; begin readln(n,m); for i:=1 to n do read(fun[i]); for i:=1 to m do begin readln(x,y,z); new(k); k^.data:=y; k^.sum:=z; k^.next:=map[x]; map[x]:=k; end; l:=0;r:=10000; while (r-l>0.001) do begin fillchar(v,sizeof(v),false); fillchar(num,sizeof(num),0); mid:=(l+r)/2; if spfa(1) then l:=mid else r:=mid; end; writeln(l:0:2); end.
bzoj1690:[Usaco2007 Dec]奶牛的旅行(分数规划+spfa判负环)
标签:
原文地址:http://www.cnblogs.com/Sakits/p/5469300.html