noip模拟赛 钻石

分析:用裸暴力可以得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\n", f[n][i]);

    return 0;
}

 

posted @ 2017-10-20 14:33  zbtrs  阅读(178)  评论(0编辑  收藏  举报