大家所熟知的01背包ä¸è¦æ±‚输入是一个实数,两个整数,å³èƒŒåŒ…容é‡å’Œç‰©å“体积都是整数,而物å“价值å¯ä»¥æ˜¯å®žæ•°ï¼Œè¿™æ—¶å¯ä»¥å¯¹è¿™ä¸ªæ•´æ•°éƒ¨åˆ†å³ä½“积进行枚举,实现动æ€è§„划,å³å°†å‰i个物å“装入容é‡ä¸ºj的背包所能的最大价值为dp[i][j]=max(dp[i-1][j],dp[i-1][j-v(i)]+w(i))
,这个方法至少有两个局é™ï¼Œ
1ã€ç”±äºŽè¯¥ç®—æ³•çš„æ—¶é—´å¤æ‚度为O(i*j),i为物å“个数,j为背包容é‡ï¼Œæ¤æ—¶å½“ç‰©å“æ•°é‡å¹¶ä¸å¤šæœ¬åº”该是个简å•问题的时候,å´å¾€å¾€ç”±äºŽèƒŒåŒ…容é‡è¿‡å¤§è€Œå¯¼è‡´æ—¶é—´å¤æ‚度很高,
2ã€ç”±äºŽèƒŒåŒ…容é‡jå’Œæ¯ä¸ªç‰©å“的物å“体积v(i)éƒ½è¢«ç”¨ä½œäº†ä¸‹æ ‡ï¼Œæ‰€ä»¥è¢«é™åˆ¶ä¸ºæ•´æ•°ï¼Œåœ¨å¾ˆå¤šæƒ…å†µä¸‹ï¼Œå¦‚æžœå‡ºçŽ°å°æ•°ï¼Œå¸¸è§çš„åšæ³•æ˜¯å°†å°æ•°æŒ‰æ¯”例放大,将其转æ¢ä¸ºä¸€ä¸ªæ•´æ•°çš„背包问题,但对于高精度的,或个别数æ®é«˜ç²¾åº¦çš„æƒ…况很显然ä¸èƒ½ç”¨è¿™ç§æ–¹æ³•,
以下是王晓东《算法设计与分æžã€‹ä¹¦ä¸çš„一个实数背包问题åŠå…¶ç®—法æ€è€ƒ
设二元数组集p,åˆå€¼ä¸ºp={(0,0)},代表装入0个物å“,但用背包容é‡ä¸º0,拥有价值为0,之åŽå¯¹æ‰€æœ‰ç‰©å“进行枚举,将枚举到的物å“çš„ä½“ç§¯åŠ åœ¨å®¹é‡ä¸Šè¾¹ï¼Œå°†ä»·å€¼åŠ åœ¨æ•´ä½“ä»·å€¼ä¸Šè¾¹ï¼Œæž„æˆä¸€ä¸ªæˆ‘们å‡è±¡çš„讲该物体装入背包åŽçš„æ•ˆæžœå³äºŒå…ƒæ•°ç»„集q={p+(v(i),w(i))},其ä¸å¦‚果出现整体体积已ç»å¤§äºŽèƒŒåŒ…容é‡çš„æƒ…况就将其èˆå¼ƒï¼ŒåŒæ—¶ç”±äºŽæˆ‘ä»¬æ— æ³•ä¿è¯æˆ‘ä»¬ç¡®å®žè¦æŠŠè¿™ä¸ªç‰©å“装入背包,于是我们ä¿ç•™äº†åŽŸæœ‰çš„è¯¥ç‰©ä½“æœªè£…å…¥èƒŒåŒ…çš„æƒ…å†µp,然åŽå°†p与q组æˆå¹¶é›†ï¼Œè¿™å°±ä»£è¡¨äº†å½“剿‰€æœ‰æƒ…å†µï¼ŒæŽ¥ç€æˆ‘们é‡å¤ä¸Šè¿°æ¥éª¤è¿›è¡Œä¸‹ä¸€ä¸ªç‰©å“的枚举,直到所有物å“éƒ½æžšä¸¾å®Œæ¯•ï¼Œæˆ‘ä»¬ä¾¿å¾—åˆ°äº†æœ€ä¼˜è§£ã€‚åŒæ—¶ï¼Œè¿™é‡Œè¾¹æœ‰ä¸€ä¸ªé‡è¦çš„剪æžï¼Œå°±æ˜¯å¦‚果我们能以更å°çš„体积获得更大的价值那么那个用了更多体积å´åªå¾—到更少价值的情况就å¯ä»¥å‰ªæžäº†ï¼Œå³å¦‚æžœå˜åœ¨ä¸¤ä¸ªäºŒå…ƒç»„(a,b)
,(c,d)
,满足a<=c && b>d
,那么二元组(c,d)
å¯ä»¥èˆå¼ƒï¼Œå…·ä½“例å如下:
起始状æ€ä¸ºï¼ˆ0,0),放入一个新的物体åŽï¼Œäº§ç”Ÿä¸€äº›æ–°çš„状æ€ã€‚
容é‡ä¸º10,有5个物体,é‡é‡ä¸º3 5 1 9 7,价值为11 28 6 49 35。则二元组集pçš„å˜åŒ–为
åŠ å…¥ç¬¬1个物体时
p={(0,0),(3,11)}
åŠ å…¥ç¬¬2个物体时
p={(0,0),(3,11),(5,28),(8,39)}
åŠ å…¥ç¬¬3个物体时
p={(0,0),(1,6),(4,17),(5,28),(6,34),(8,39),(9,45)}
åŠ å…¥ç¬¬4个物体时
p={(0,0), (1,6),(4,17),(5,28),(6,34),(8,39),(9,49),(10,55)}
åŠ å…¥ç¬¬5个物体时
p={(0,0), (1,6),(4,17),(5,28),(6,34), (7,35) ,(8,39), (9,49),(10,55)}
剪æž1:已放物体的总é‡é‡è¶…过背包体积,剪æž
剪æž2:å˜åœ¨(Ai,Bi),(Aj,Bj),如果Ai
æ ¹æ®å‰ªæžï¼šå°†ç‰©ä½“æŒ‰ä½“ç§¯ä»Žå¤§åˆ°å°æŽ’åºï¼Œä»·å€¼ä»Žå¤§åˆ°å°æŽ’åºã€‚
å…³äºŽè¯¥ç®—æ³•çš„æ—¶é—´å¤æ‚度,应该是O(2n ),如王晓东书上所说,集åˆpæ˜¯é€šè¿‡å¯¹ç‰©å“æžšä¸¾æ”¾å…¥èƒŒåŒ…与å¦çš„æ‰€æœ‰çжæ€çš„一ç§å±•ç¤ºï¼Œæœ€åæ˜¯2n ï¼Œå³æ¯ä¸€ä¸ªç‰©å“éƒ½ä¸æ»¡è¶³å‰ªæžæ¡ä»¶ï¼Œé›†åˆpä¼šæŒ‡æ•°çº§çš„æ‰©å¼ ï¼Œä½†æ˜¯è¿™ç§æƒ…况应该是æžå°‘æ•°å§ï¼Œæ£å¦‚网上所æµä¼ çš„ï¼Œä¼ è¯´è¿™ä¸ªç®—æ³•çš„å¹³å‡æ—¶é—´å¤æ‚度是n2.4 。
//算法实现,迥异于王晓东书上的那段诡异的代ç 。。。。。。
#include <stdio.h>
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;
double cost[1000];
double value[1000];
int n,v;
struct point{
double capacity;
double worth;
point(double a=0,double b=0){capacity=a;worth=b;}
};
list<point> p;
list<point> q;
list<point> r;
void ptoq(int i)
{
q.clear();
list<point>::iterator it;
double tempcap;
double tempval;
for(it=p.begin();it!=p.end();++it)
{
tempcap=(*it).capacity+cost[i];
tempval=(*it).worth+value[i];
point temp(tempcap,tempval);
if(tempcap<=v)
q.push_back(temp);
}
}
void marriage()
{
r.clear();
list<point>::iterator itp,itq;
itp=p.begin();
itq=q.begin();
while(itp!=p.end() && itq!=q.end())
{
if((*itp).capacity>(*itq).capacity)
{
if(r.empty() || (*itq).worth>r.back().worth)
r.push_back(*itq);
itq++;
}
else if((*itp).capacity<(*itq).capacity)
{
if(r.empty() || (*itp).worth>r.back().worth)
r.push_back(*itp);
itp++;
}
else
{
if((*itp).worth>(*itq).worth)
{
if(r.empty() || (*itp).worth>r.back().worth)
r.push_back(*itp);
}
else
{
if(r.empty() || (*itq).worth>r.back().worth)
r.push_back(*itq);
}
itq++;
itp++;
}
}
while(itp!=p.end())
{
if(r.empty() || (*itp).worth>r.back().worth)
r.push_back(*itp);
itp++;
}
while(itq!=q.end())
{
if(r.empty() || (*itq).worth>r.back().worth)
r.push_back(*itq);
itq++;
}
p=r;
}
int main()
{
int i;
scanf("%d%d",&n,&v);
for(i=1;i<=n;++i)
scanf("%lf%lf",&cost[i],&value[i]);
point tmp(0,0);
p.push_back(tmp);
ptoq(1);
for(i=2;i<=n;++i)
{
marriage();
ptoq(i);
}
marriage();
printf("%lf",p.back().worth);
return 0;
}