01分數規劃是這樣的一類問題,有一堆物品,每乙個物品有乙個收益ai,乙個代價bi,我們要求乙個方案使選擇的$\sum/\sum$最大。
首先我們來一道例題吧,01分數規劃的大體方法都是一樣的。
例1 dropping tests poj2976
給出n個物品,每個物品有兩個屬性a和b,選擇n-k個元素,詢問$\sum/\sum$的最大值。
1<=n<=1000,0<=k首先這題顯然是茲磁二分的,而$\sum/\sum \geq x$就等價於$\sum-x\sum \geq 0$。
所以我們發現二分完把ai-x*bi排序後把最大的n-k個選出來就行了。
#include #include#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
int n,k,a[2333],b[2333
];double ps[2333
];bool ok(double
x)void
sol()
printf(
"%.0lf\n
",l*100);}
intmain()
但是還有一種神奇的做法,既然我們可以二分乙個值,而且得出乙個更優的解,那麼我們就可以在這個解的基礎上繼續做,直到滿足精度。
#include #include#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
intn,k;
struct pro s[233333
];bool
operator
< (pro a,pro b)
double sol(double
x)void
sol()
while(fabs(l-ans)>1e-6
);
if(l>1) l=1
;
if(l<0) l=0
; printf(
"%.0lf\n
",l*100);}
intmain()
例2 desert king poj2728
(模型有轉化)
給出乙個n個點的完全圖,每條邊有兩個權值cost和len。
求乙個生成樹使$\frac}}$最小。
2<=n<=1000
還是二分答案x,把每條邊邊權設為cost-x*len,跑最小生成樹,判答案的正負。建議用prim跑,複雜度比較科學。
#include #include#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
typedef
long
double
ld;#define sz 1066
intn,xx[sz],yy[sz],hh[sz],fm[sz];
bool
del[sz];
ld mind[sz],d[sz][sz],d1[sz][sz],d2[sz][sz];
ld sqr(ld x)
ld abs(ld x)
bool
ok(ld x)
for(int i=0;i<=n;i++) mind[i]=1000000000, del[i]=0
; mind[
1]=0; fm[1]=0
; ld ans=0
;
for(int i=1;i<=n;i++)
ans+=d[fm[mp]][mp]; del[mp]=1
;
for(int j=1;j<=n;j++)
}return ans<=0;}
void
sol()
}ld l=0,r=1000000000
;
while(r-l>1e-6
)
printf(
"%.3lf\n
",(double
)l);
}int
main()
直接迭代
#include #include#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
#define sz 1066
intn,xx[sz],yy[sz],hh[sz],fm[sz];
bool
del[sz];
double
mind[sz],d[sz][sz],d1[sz][sz],d2[sz][sz];
double sqr(double x)
double abs(double x)
double sol(double
x)
for(int i=0;i<=n;i++) mind[i]=1000000000, del[i]=0
; mind[
1]=0; fm[1]=0
;
double aa=0,bb=0
;
for(int i=1;i<=n;i++)
aa+=d1[fm[mp]][mp];
bb+=d2[fm[mp]][mp];
del[mp]=1
;
for(int j=1;j<=n;j++)
}return aa/bb;
}void
sol()
}double l,ans=0
;
dowhile(fabs(l-ans)>1e-6
); printf(
"%.3lf\n
",l);
}int
main()
例3 sightseeing cows poj3621
給出乙個有l個點p條邊的有向圖,每個點上有點權f,每條邊上有邊權t。
求乙個迴路使$\frac}}$最大。
2<=l<=1000,2<=p<=5000。
因為環上邊和點數相等,我們可以直接把邊權當做花費,入點的點權當作收入。
然後還是二分答案建圖,判圖中有沒有正環。取個反就成了判負環。
dfs版spfa即可。
#include #include#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
#define sz 666666
int n,m,v[sz],fst[sz],vb[sz],nxt[sz],vc[sz],m=0
,x;bool vis[sz],fh=0
;double
dist[sz];
void adde(int a,int b,int c)
void dfs(int p,double
x) dist[vb[e]]=c+dist[p];
dfs(vb[e],x);
if(fh) return
; }
vis[p]=0;}
bool ok(double
x)
return0;
}int
main()
double l=0,r=1000000000
;
while(r-l>1e-6
)
printf(
"%.2lf\n
",l);
}
迭代的話…似乎不太好寫,就算了吧
0 1分數規劃
題目鏈結 中文鏈結 附一篇大佬部落格感覺講的不錯 0 1分數規劃,不妨設 l a i b i 題目要求要讓結果最大,那麼就是l最大最終移相化簡可得 a i l b i 0,因為a 和b都是已知所以我們可以直接列舉l,當我們所求的值大於零說明l還有更優解當小於零時l沒有最優解。直接二分即可 inclu...
01分數規劃
01分數規劃,就是這樣乙個東西 max frac 其中 xi in 簡而言之,就是在n個物品中選出任意幾個 或者可以有限制選多少個 使得其兩種權值a,b的比值最大 這樣的問題可以二分解決 假如有這樣一道裸題 poj2976,選n k個物品使得比值最大 我們二分出r,若存在 frac r 則r可行 變...
01分數規劃
已經接觸過01分數規劃但是只知道二分寫法 實際求解略慢 dinkelbach演算法還是值得一學的。上一道裸的01分數規劃吧。poj x陣列代表我們選或者不選 0,1構成 r sigma a i x i sigma b i x i 變形 設f v 為 sigma a i x i sigma b i x...