超简单背包问题动态规划之三国篇

原创声明:

 

本故事纯属虚构,如有雷同,纯属巧合。

撸二儿眉头紧锁,盯着电脑屏幕一言不发。

我凑上前儿一瞧,哎呀,正是《三国演义》第四十一回,“刘玄德携民渡江,赵子龙单骑救主”!却说这刘备携百姓弃新野,走攀城,又欲奔襄阳暂避,奈何蔡瑁拒不打开城门,只得转向江陵。途中遇刘表墓,复又伏前痛哭~

众将劝他:”今拥民众数万,日行十余里,似此几时得至江陵?倘曹兵到,如何迎敌?不如暂弃百姓,先行为上!”,刘备哭着说:“举大事者必以人为本。今人归我,奈何弃之?”

百姓闻玄德此言莫不伤感!

这时一位老父上前:”将军仁义,吾等皆愿跟随将军。怎奈吾包裹破旧,不能负重,欲择选数件背之,余弃之,将军可帮老朽定夺?”

刘备答曰“备不才,愿一试!”。

说着走到行李处,老父指道:“此处有一玉壶,重二两,值六两银子;一烟斗,重二两,值三两银子;一石器,重六两,值五两银子;一铁斧,重五两,值四两银子;一宝砚,重四两,值六两银子。老朽此包只得承载十两,将军可有良策,使吾负有所值?”

玄德暗忖道“倘若孔明在此,可询之。奈何先生与二弟前往江夏求救于公子琦,不在吾之左右,为之奈何啊?”

撸二儿看到此处,抓耳挠腮!

我见状,打趣道“盖闻撸二儿有经天纬地之才,扭转乾坤之力,匡扶宇宙之功…blablalba,公可有一策,以助玄德公?”

撸二儿听地得意洋洋,答道“汝所言赞美之词,不过书中寻章摘句,笔下虽有千言,胸中实无一策,此小儿之问,汝竟不知,亦不过如此耳!”

我悻悻道“愿闻其详!”

撸二儿愈加兴奋答道“汝可先列下表:

序号

1

2

3

4

5

物品

玉壶

烟斗

石器

铁斧

宝砚

重量(W)

2

2

6

5

4

价值(V)

6

3

5

4

6

然后每个物品试之,皆列出如下可行之策:

策一:物品1

策二:物品2

策三:物品3

策四:物品4

策五:物品5

策六:物品1 + 物品2

策七:物品1 + 物品3

…….

如此这般,列出所有可选之策,择其最优,岂不解之?”

撸二儿说完,愈发得意起来。

我答道“此虽好,算起来未免复杂,每物有两态,可选或不可选,即:

2*2*……*2 = 2^n;

n

亦即共需计算2^n次,此法未免计算过多啊?”

撸二儿低头沉思,半响问道“公可有良策?”

我又说道“公饱读诗书,每日自比于管仲,乐毅……blablabla~”

撸二儿急忙起身腾出椅子,双手作楫道“小生狂妄,在此班门弄斧,为先生所笑!愿先生不与小儿之见,还望教之!”

我看撸二儿态度诚恳,不忍戏之,便执笔说道“汝可取建立以下模型:

最大的价值:MAX = max( V1X1 + V2X2 + …+ VnXn);

V1,V2,V3…Vn为每物价值;X1,X2,…Xn为0或1;

约束条件:W1X1 + W2X2 +…+ WnXn <Capacity;

W1,W2,…Wn为每物重量;Capacity为包裹承重最大值;

定义当前状态价值:V(i,j);

此值表明第i个物品,当前包裹承重为j时最佳组合对应的价值;

对第i个物品的判断,可分为以下两种情况:

情况一:当前包裹承重j小于物品重量Wi,此时的价值与前i-1的物品价值相等,即

V(i,j ) =V(i-1,j);

情况二:当前包裹承重j大于等于物品重量Wi,此时若选择拿,则:

V(拿) = V(i,j) = V(i-1,j – Wi) + Vi;

若选择不拿,则与前i-1个物品价值相等,则:

V(不拿) = V(i,j) = V(i-1,j)

取V(拿)与V(不拿)大者即可。 

据此填出下表T1:

序号

1

2

3

4

5

物品

玉壶

烟斗

石器

铁斧

宝砚

重量(W)

2

2

6

5

4

价值(V)

6

3

5

4

6

T1

i/j

0

1

2

3

4

5

6

7

8

9

10

0

0

0

0

0

0

0

0

0

0

0

0

1

0

0

6

6

6

6

6

6

6

6

6

2

0

0

6

6

9

9

9

9

9

9

9

3

0

0

6

6

9

9

9

9

11

11

14

4

0

0

6

6

9

9

9

10

11

13

14

5

0

0

6

6

9

9

12

12

15

15

15

不难看出,V(0,j) = V(i,0) = 0,(i,j = 0,1,2…10);

V(1,1):j = 1 < W1 = 2,即V(1,1) = V(0,1) = 0,故取0填入上表V(1,1);

V(1,2):j = 2 = W1 = 2,即V(拿)= V(0,0) + V1 = 6,

                                            V(不拿) = V(0,2) = 0,

                                            V(拿) > V(不拿),故取6填入上表V(1,2);

V(1,3):j = 3 > W1 = 2,即V(拿) = V(1,1) + V1 = 6,

                                           V(不拿) =V(0,3) = 0,

                                           V(拿) > V(不拿),故取6填入上表V(1,3);

以此推之,如

V(4,7):j = 7 > W4 = 5,即V(拿) = V(3,2) + V4 = 6 + 4 = 10,

                                          V(不拿) =V(3,7) = 9,

                                          V(拿) > V(不拿),故取10填入上表V(4,7);

汝填完此表,汝即可知选择物品得到的最大价值!”

撸二儿得此表,聚精会神地填写起来~

须庾,表填毕,撸二儿拿起表来,捻须好一番审视!

“先生,小生还有一问。”撸二儿问道,

“汝但问无妨!”我爽快地答道。

“此虽能获得所选之物最大价值,却不能得出所选物品,还请先生赐教。”撸二儿问道。

“好,及俺给你道来!”我按在桌台上又问道:

“汝可知,选择物品最大价值在何处?”我问道,

“余观表T1可知,所取最大值在V(5,10),V(5,9)V(5,8)处。”撸二儿答道。

“善!既如此,不妨取V(5,10)以观之:

V(5,10) ≠ V(4,10),即已取物品5,而又观:

V(5,10) = V(4,6) + V5 = 9 + 6 = 15,知:

V(5,10)上一状态为V(4,6)

循此法,即可知所选之物为5、2、1,具以表T2以示。”我缓缓说来。

T2

i/j

0

1

2

3

4

5

6

7

8

9

10

0

0

0

0

0

0

0

0

0

0

0

0

1

0

0

6

6

6

6

6

6

6

6

6

2

0

0

6

6

9

9

9

9

9

9

9

3

0

0

6

6

9

9

9

9

11

11

14

4

0

0

6

6

9

9

9

10

11

13

14

5

0

0

6

6

9

9

12

12

15

15

15

“得遇先生所论,甚善,待吾乘时间机器到那三国,以助玄德公!”说罢,撸二儿自念咒语“ѾѽѺѨѩҚXLѤҀSHAҁӁ!”念完风起云滚,忽得一道闪电,携撸二儿一同进入到那荧幕中~

刘备正愁眉莫展,忽得一阵怪风袭来!

飘飘然来一位鹤发单颜的老者,对备曰“将军莫虑,如在下给你道来~~”,这位仙风道骨的老者正是撸二儿,他教以刘备如是这般,使得备顷刻茅塞顿开!

说完,撸二儿正欲归来,备扯着撸二儿的袖子道“备遇先生,如久旱遇甘霖…blablabla~”

附代码/C++

//背包问题
//给定n种物品和一个容量为Capacity的背包,物品i的重量是wi,其价值为vi
const int VNUM = 6;
const int WNUM = 6;
const int CAPACITY = 10;
int values[VNUM] = {0,6,3,5,4,6};
int weights[WNUM] = {0,2,2,6,5,4};
int maxvalue[VNUM][CAPACITY+1] = {0};
int MaxValue(){
	int i,j;
	for (i = 1; i <= VNUM; i++) {
		for (j = 1; j <= CAPACITY; j++) {
			//剩余空间不够装
			if (j < weights[i]) {
				maxvalue[i][j] = maxvalue[i-1][j];
			}
			//剩余空间可装
			else {
				//选择装与不装之间中的较大值
				maxvalue[i-1][j] > (maxvalue[i-1][j-weights[i]] + values[i]) ?
					maxvalue[i][j] = maxvalue[i-1][j] :
					maxvalue[i][j] = maxvalue[i-1][j-weights[i]] + values[i];
				}
			}
		}
	return maxvalue[VNUM-1][CAPACITY];
	}


//查找哪些物品被选入
int items[VNUM] = {0};
void Find(int i,int j) {
	if (i < 1) return;
	if (maxvalue[i][j] == maxvalue[i-1][j]) {
		items[i] = 0;    //与未选状态相等,不选
		Find(i-1,j);
		}
	else if( j >= weights[i] && maxvalue[i][j] == maxvalue[i-1][j-weights[i]] + values[i]) {
		items[i] = 1;    //与未选状态不等,找出上一状态
		Find(i-1,j-weights[i]);
		}
	}


(以上内容若有不严谨,错误之处,欢迎各位大佬指正,感激不尽!)

本文版权所有,如有转载,请注明出处,谢谢!

更多内容,请扫下方二维码查看,感谢您的支持!!!

 

猜你喜欢

转载自blog.csdn.net/feengg/article/details/80249071