分析:用裸暴力可以得60分,每次dfs,看第i个盒子到底有没有钻石就行了.其实这很像0/1背包问题,只是多了一个m的限制.这要怎么办呢?因为概率是可以加减的,所以可以先不考虑m的限制,求出概率,然后dfs一遍把money < m的概率给减掉就好了.
正解是meet in the middle,dp+dfs跑的比正解还快.
如果有的题多个限制不好处理,但是要求的东西满足线性性,那么可以先求出所有的情况的答案,然后把不满足限制的给减掉.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n, m, v[40], p[40]; double f[40][40]; void dfs(int dep, double gailv, int sum, int num) { if (sum >= m) return; if (dep == n + 1) { if (sum < m) f[n][num] -= gailv; return; } dfs(dep + 1, gailv * (double)p[dep] / 100, sum + v[dep], num); dfs(dep + 1, gailv * (double)(100 - p[dep]) / 100, sum, num + 1); } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d%d", &v[i], &p[i]); f[1][0] = (double)p[1] / 100; f[1][1] = (double)(100 - p[1]) / 100; for (int i = 2; i <= n; i++) for (int j = 0; j <= i; j++) { if (j - 1 >= 0) f[i][j] += f[i - 1][j - 1] * (double)(100 - p[i]) / 100.0; f[i][j] += f[i - 1][j] * (double)p[i] / 100.0; } dfs(1, 1.0, 0, 0); for (int i = 0; i <= n; i++) printf("%.3lf ", f[n][i]); return 0; }