关于01分数规划的具体讲解和例题分析,推荐相当好的博客:http://www.cnblogs.com/perseawe/archive/2012/05/03/01fsgh.html
这里不再赘述
所以这里只是简单粗暴的贴代码
poj 2976
题目的要求是求比值最大,限制是所取得数量为n-k,所以只需要将d排序取前n-k个即可
注意:数据结束的条件是(n=0) && (k=0),但是在读入的时候不能判断 while (n<>0) and (k<>0) ,因为会存在合法的输入使得 n<>0 && k=0 ,所以数据结束的条件是(n<>0)
二分方法:
const
eps=1e-6;
var
n,m,k :longint;
i :longint;
tmp,l,r,mid :double;
a,b :array[0..1010] of longint;
d :array[0..1010] of double;
procedure sort(l,r:longint);
var
i,j:longint;
x,y:double;
begin
i:=l; j:=r; x:=d[(l+r)>>1];
while (i<=j) do
begin
while d[i]>x do inc(i);
while d[j]l then sort(l,j);
end;
begin
read(n,k);
while (n<>0) do
begin
for i:=1 to n do read(a[i]);
for i:=1 to n do read(b[i]);
m:=n-k;
r:=0;
for i:=1 to n do if a[i]/b[i]>r then r:=a[i]/b[i];
l:=0;
while (r-l>=eps) do
begin
mid:=(l+r)/2;
for i:=1 to n do d[i]:=a[i]-mid*b[i];
sort(1,n);
tmp:=0;
for i:=1 to m do tmp:=tmp+d[i];
if tmp>0 then l:=mid else r:=mid;
end;
writeln(round(l*100));
read(n,k);
end;
end.
const
eps=1e-6;
var
n,m,k :longint;
i :longint;
l,ans :double;
p,q :int64;
a,b,c :array[0..1010] of longint;
d :array[0..1010] of double;
procedure sort(l,r:longint);
var
i,j:longint;
z:longint;
x,y:double;
begin
i:=l; j:=r; x:=d[(l+r)>>1];
while (i<=j) do
begin
while d[i]>x do inc(i);
while d[j]l then sort(l,j);
end;
begin
read(n,k);
while (n<>0) do
begin
for i:=1 to n do read(a[i]);
for i:=1 to n do read(b[i]);
m:=n-k;
l:=1;
repeat
ans:=l;
for i:=1 to n do
begin
d[i]:=a[i]-l*b[i]; c[i]:=i;
end;
sort(1,n);
p:=0; q:=0;
for i:=1 to m do
begin
inc(p,a[c[i]]);
inc(q,b[c[i]]);
end;
l:=p/q;
until abs(l-ans)
poj 2728
最优比率生成树,题目要求是比率最小,题目的限制是树,所以我们用prim来记录我们选择的边(这种图真的不建议用kruscal...),Dinkelbach算法会比二分快,所以这里就只写了Dinkelbach算法,注意每次都要更新a、b、d数组const
eps=1e-6;
var
n,pos,ta :longint;
l,ans,p,q,tt :double;
tb,td :double;
i,j :longint;
x,y,z,a :array[0..1010] of longint;
flag :array[0..1010] of boolean;
b,d :array[0..1010] of double;
begin
read(n);
while (n<>0) do
begin
for i:=1 to n do read(x[i],y[i],z[i]);
l:=0;
repeat
ans:=l; p:=0; q:=0;
for i:=2 to n do
begin
a[i]:=abs(z[i]-z[1]);
b[i]:=sqrt(sqr(x[i]-x[1])+sqr(y[i]-y[1]));
d[i]:=a[i]-l*b[i];
end;
fillchar(flag,sizeof(flag),false);
flag[1]:=true;
for i:=1 to n-1 do
begin
tt:=1e9;
for j:=2 to n do
if not flag[j] and (d[j]
最优比率环,题目要求比率最大,没啥限制,只要存在正环就说明还有更优的答案。将边建成负的,这样判正环就变成了判负环,由于数据范围并不是很大,所以就用了Bellman_ford。这类题只用二分
const
eps=1e-6;
var
n,m :longint;
l,r,mid :double;
i :longint;
a :array[0..1010] of longint;
x,y,b :array[0..5010] of longint;
d :array[0..5010] of double;
dis :array[0..1010] of double;
function bellman_ford(l:double):boolean;
var
i,j:longint;
flag:boolean;
begin
for i:=1 to m do d[i]:=-(a[x[i]]-l*b[i]);
for i:=1 to n do dis[i]:=0;
for i:=1 to n do
begin
flag:=false;
for j:=1 to m do
if (dis[x[j]]+d[j]=eps) do
begin
mid:=(l+r)/2;
if bellman_ford(mid) then l:=mid else r:=mid;
end;
if l>eps then writeln(l:0:2) else writeln(0);
end.
最优比率环,题目要求比率最小,也没啥其他限制。这次就直接建边判负环就行了,这数据范围相当卡,所以用dfs版spfa判负环...
const
eps=1e-9;
var
n,m,ll,x,y,z :longint;
i :longint;
l,r,mid :double;
vis :array[0..3010] of boolean;
last :array[0..3010] of longint;
pre,other,len :array[0..10010] of longint;
dis :array[0..3010] of double;
flag :boolean;
procedure connect(x,y,z:longint);
begin
inc(ll);
pre[ll]:=last[x];
last[x]:=ll;
other[ll]:=y;
len[ll]:=z;
end;
procedure dfs(x:longint;l:double);
var
p,q:longint;
begin
if flag then exit;
vis[x]:=true;
q:=last[x];
while (q<>0) do
begin
if flag then exit;
p:=other[q];
if dis[p]>dis[x]+len[q]-l then
begin
dis[p]:=dis[x]+len[q]-l;
if vis[p] then
begin
flag:=true;exit;
end else dfs(p,l);
end;
q:=pre[q];
end;
vis[x]:=false;
end;
function check(x:double):boolean;
var
i:longint;
begin
flag:=false;
for i:=1 to n do dis[i]:=0;
for i:=1 to n do vis[i]:=false;
for i:=1 to n do
begin
dfs(i,x);
if flag then exit(true);
end;
exit(false);
end;
begin
read(n,m);
for i:=1 to m do
begin
read(x,y,z);
connect(x,y,z);
end;
l:=0; r:=1e7;
while (r-l>=eps) do
begin
mid:=(l+r)/2;
if check(mid) then r:=mid else l:=mid;
end;
writeln(r:0:8);
end.
——by Eirlys