您的位置:首页 > 其它

BZOJ 1076 [SCOI2008]奖励关 - 状压DP+数学期望

2017-08-18 01:17 483 查看
看了数据范围一目了然是状态压缩,然而对于每种情况有选和不选两种情况,记录已选的状态,每次枚举关卡时判断是否已选。

注意这种最优选择一般都采取倒序才能排除掉一些不可预知的不合法情况,我正序写了仨小时不合法情况还是没排净233.

第一份代码打表筛出了一些数量合法的情况,其实如果逆推,不可能累加到初始条件上,还是程序变得异常的慢(大概又是垫底的速度吧啊哈哈)。

期望的话,大概就是 当前得分期望=上一轮得分期望+这一轮得分m (感谢slongle_amazing的公式),于是全部除以m即可。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>

using namespace std;

const int maxn=105;
const int maxm=17;

int n,m,cnt;
int s[maxm];
double dp[maxn][70000];
int node[maxm];
int shaker[1<<maxm];

int getnum(int x)
{
int res=0;
while(x)
{
x&=x-1;
res++;
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<(1<<(m+1));i++)
{
if(getnum(i)>n)continue;
shaker[++cnt]=i;
}
for(int i=1;i<=m;i++)
{
int k;
scanf("%d",s+i);
while((~scanf("%d",&k))&&k)
node[i]|=(1<<(k-1));
}
for(int i=n;i>=1;i--)
for(int j=1;j<=cnt;j++)
{
for(int k=1;k<=m;k++)
{
if((shaker[j]&node[k])==node[k])
dp[i][shaker[j]]+=max(dp[i+1][shaker[j]],dp[i+1][shaker[j]|(1<<(k-1))]+s[k])/m;
else dp[i][shaker[j]]+=dp[i+1][shaker[j]]/m;
}
}
printf("%.6lf",dp[1][0]);//终止条件
}



#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>

using namespace std;

const int maxn=105;
const int maxm=17;

int n,m;
int s[maxm];
double dp[maxn][70000];
int node[maxm];

int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int k;
scanf("%d",s+i);
while((~scanf("%d",&k))&&k)
node[i]|=(1<<(k-1));
}
for(int i=n;i>=1;i--)
for(int j=0;j<(1<<m);j++)
{
for(int k=1;k<=m;k++)
{
if((j&node[k])==node[k])
dp[i][j]+=max(dp[i+1][j],dp[i+1][j|(1<<(k-1))]+s[k])/m;
else dp[i][j]+=dp[i+1][j]/m;
}
}
printf("%.6lf",dp[1][0]);//终止条件
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: