今天北京电子科技学院的一网友问我一题,我面熟,说用dp,可发现自己对dp理解不是很好,现在拿出买的《ACM程序设计培训教程》看到背包问题有那么多解法,现在学习中……
小明假期同爸爸一起去书店,他选中了n本书,每本书的单价分别为:P1、P2、P3……Pn。不巧的是,小明的爸爸只带了M元钱,为了让小明渡过一个愉快的假期,爸爸仍然同意买书,但有一个要求,要小明从n本书中选出若干本,使得单价相加所得的和同M元最接近。你能够帮助小明解决这个问题吗?
要求:总钱数M、书本数n以及各本书的价格从键盘或文件输入;如果有多种组合,应全部列出。 现在还有一个要求:就是小明对每一种书都有一个兴趣度,从键盘输入,如果有相同的总价格,则考虑他们的总兴趣度,选择兴趣度大的输出。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
1
#include <stdio.h>
2![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
#define MAX 51
4
struct booksinfo
5![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
6
float price;
7
float v;
8
int flag;
9
}books[MAX];
10![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
11
int main(void)
12![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
13
int i, j, k, m, n;
14
int a[MAX];//标志要哪几本
15
float total;
16
int count = 0, pn;
17
float max = -1, sum;
18![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19
printf("input number of money: ");
20
scanf("%f", &total);
21
printf("input number of books: ");
22
scanf("%d", &n);
23
printf("input price and value: ");
24
for (i = 0; i < n; i++)
25![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
26
scanf("%f%f", &books[i].price,&books[i].v);
27
books[i].flag = i+1;
28
}
29![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
30
m = 1;
31
k = 1;
32
for (i = 1; i < n; i++)//枚举
33![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
34
m = m * 2 + 1;
35
k <<= 1;
36
}
37![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
38
for (i = 1; i <= m; i++)//符合i的取书情况的就统计
39![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
40
pn = 0;
41
sum = 0;
42
for (j = 1; j <= k; j <<= 1)
43![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
44
if ((i & j) == j)
45![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
46
sum += books[pn].price;
47
if (sum > total)
48
break;
49
}
50
pn++;
51
}
52![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
53
if (sum <= total)
54![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
55
if (sum > max)
56![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
57
count = 1;
58
a[count - 1] = i;
59
max = sum;
60
}
61
else if (sum == max)//增加一种
62![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
63
count++;
64
a[count - 1] = i;
65
}
66
}
67
}
68![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
69
printf("%d groups\n", count);
70
max = 0;
71
for (i = 0; i < count; i++)
72![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
73
sum = 0;
74
pn = 0;
75
for (j = 1; j <= k; j <<= 1)
76![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
77
if ((a[i] & j) == j)//与a[i]取书相同的情况就输出
78![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
79
printf("%f ", books[pn].price);
80
sum += books[pn].v;
81
}
82
pn++;
83
}
84
if (sum > max)
85![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
86
m = a[i];
87
max = sum;
88
}
89
printf("\n");
90
}
91
printf("the max interesting:\n");
92
for (j = 1; j <= k; j <<= 1)
93![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
94
pn = 0;
95
if ((m & j) == j)
96
printf("%f ", books[pn].price);
97
pn++;
98
}
99
printf("\n");
100
// system("pause");
101
}
102![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
用二进制位来标志买了哪本书,例如n=6,则需要2的0次方+……2的五次方,共6位,用k标示,m则为穷举的次数,一共有m种情况,用&就知道该本书在不在选择的范围之内,然后再选择最优的策略。我的代码最后interesting输出不出来,不知道怎么回事。这几天太忙,过两天再来看看。还有flag我想输出书的标号的,但是最后输出的是价格,想输出书的标号改一下就ok了。