回溯方法是正确的,但是LTE
#include <iostream>
using namespace std;
inline void offer(int w[], float v[], int n, int& sum, int i,float &mmin, int total, float& c) {
if (i == n) {
if (c < mmin)
mmin = c;
return;
}
//左子树
if (sum + w[i] <= total) {
sum += w[i];
float tmp = c;
c *= 1 - v[i];
offer(w, v, n, sum, i+1, mmin, total, c);
sum -= w[i]; //回溯
c = tmp;
}
//右子树
offer(w, v, n, sum, i+1, mmin, total, c);
}
int w[10010];
float v[10010];
int main() {
int sum;
float mmin, c;
int m, n;
while(cin >> n >> m && (m+n)) {
for (int i = 0; i < m; i++) {
cin >> w[i] >> v[i];
}
sum = 0;
c = mmin = 1.0;
offer(w, v, m, sum, 0, mmin, n, c);
printf("%.1f%%\n", (1-mmin)*100);
}
return 0;
}
所以,不得不用DP来求解
#include <iostream>
using namespace std;
float min(float a, float b) {
if (a < b)
return a;
return b;
}
int w[10010];
float p[10010];
float DP[10010][10010] = {1};
int main() {
int m, money, i, j;
while(cin >> money >> m && (m+money)) {
for (i = 1; i <= m; ++i) {
cin >> w[i] >> p[i];
}
for (i = 1; i <= m; ++i) {
DP[i][0] = 1; //表示当没有钱的时候有i个学校,最大概率为1-p[i][0] = 0;
for (j = 1; j <= money; ++j) {
DP[0][j] = 1;
if (w[i] > j)
DP[i][j] = DP[i-1][j];
else
DP[i][j] = min(DP[i-1][j], DP[i-1][j-w[i]]*(1-p[i]));
}
}
printf("%.1f%%\n", (1-DP[m][money])*100);
}
return 0;
}
背包容量从小到大,需要一个超级庞大的数组,如果背包容量从大到小,那么只需要用一个数组即可
#include <iostream>
using namespace std;
float f[10010];
int main() {
int m, n, money;
double ans, p;
while (cin >> n >> m && (n+m)) {
for (int i = 0; i <= n; i++)
f[i] = 1;
for (int i = 1; i <= m; i++) {
cin >> money >> p;
for (int j = n; j >= money; j--) {
// f[j]指的是在第i个学校没有考虑之前,在一共有j万美元的前提下,使得一个学校都不录取的概率最低
if (f[j-money]*(1-p) < f[j]) {
f[j] = f[j-money]*(1-p);
}
}
}
printf("%.1f%%\n", (1-f[n])*100);
}
return 0;
}