杭电1203回溯+DP

回溯方法是正确的,但是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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值