您的位置:首页 > 其它

HDU 4815 Little Tiger vs. Deep Monkey (DP)2013 长春现场赛

2015-10-14 08:33 676 查看
题目链接:点击打开链接

题意:输入N个数和一个概率p,A,B两个人,B选每个数能得到其分值的概率是0.5,求A不输给B的概率不小于P的最低分数。

刚开始做这道题的时候还想着贪心,我真是太年轻了,后来又考虑概率DP,我真是太弱了。不知道现成能不能做出来这样的题,总之好失望。割!

后来看题解才发现这道题可以不用概率dp来做。我们这样考虑,让这些和的概率大,可以反着来求让剩下的数的和概率小。假设剩下的数的和最大为sum,那么我们只需求出这个最大的sum,那么那个最小和就是让总和减去他。当然也可以直接求这个最小的和。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#include <limits.h>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-8)
#define inf (1<<28)
#define sqr(x) (x) * (x)
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
const int Max=40005;
ll dp[Max];
int up=40000;
ll a[45];
int main()
{
int t,n;
double q;
cin>>t;
while(t--)
{
scanf("%d%lf",&n,&q);
for(int i=1;i<=n;i++)
scanf("%I64d",&a[i]);
memset(dp,0,sizeof dp);
dp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=up;j>=a[i];j--)
{
dp[j]+=dp[j-a[i]];//通过0/1背包求每个j(和)的频数
}
}
ll sum=0;
int p;
//for(int i=0;i<=10;i++)
//cout<<i<<" "<<dp[i]<<endl;
for(int i=0;i<=up;i++)
sum+=dp[i];
for(int i=1;i<=up+1;i++)
dp[i]+=dp[i-1];
for(p=0;p<=up;p++)
{
if(fabs((double)dp[p]/(double)sum-q)<eps||((double)dp[p]/(double)sum>q))//判断的时候是大于等于P都行
break;
}
printf("%d\n",p);
}
return 0;
}第二种做法就是概率DP了:
我们用dp[i][j]来表示B选前i题得到j分的概率,那么我们就可以通过B的概率来求A的最低分,开一个dp[41][40100]的数组,初始化dp[0][0]=1.考虑到B得分的概率为0.5,那么状态转移方程为dp[i][j+a[i]]+=dp[i][j]*0.5;dp[i-1][j]+=dp[i-1][j]*0.5;最后从dp
[0]开始统计。

#include <cstdio>
#include <cstring>

const int N = 400010;
double dp
;

int main() {
int T;
scanf("%d", &T);

while (T--) {
int n;
double p;
scanf("%d%lf", &n, &p);
for (int i = 1; i < N; ++i)
dp[i] = 0.0;
dp[0] = 1.0;
int last = 0;
for (int i = 0; i < n; ++i) {
int tmp;
scanf("%d", &tmp);
for (int k = last; ~k; --k)
dp[k + tmp] = (dp[k + tmp] + dp[k]) / 2;
for (int k = tmp - 1; ~k; --k)
dp[k] /= 2;
last += tmp;
}

double ans = 0.0;
for (int i = 0; i <= last; ++i) {
ans += dp[i];
if (ans >= p) {
printf("%d\n", i);
break;
}
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: