您的位置:首页 > 其它

Hdu 5045 Contest (状态压缩dp)

2016-08-08 13:32 344 查看

Hdu 5045 Contest (状态压缩dp) 

题意:有N个同学共同解决M道问题,每道题只能由一个同学来解决,每次花费一分钟,并且有成功率P,不能再次修改答案,任何时候不能任意两个同学做的题目数目不能相差超过1道题,有多种策略,求所有策略里最大成功期望是多少?
    分析:最优化问题,用动态规划解决,由题意,每次做题时每个人都要轮到一次,然后状态清零,用二进制表示状态,即 00000->00100 ,做到11111时要变成00000,设dp[i][j]表示当前答到第i道题并且每个同学的做题状态为j时最大的总答对概率期望,那么转移方程为
dp[i][s]= max(dp[i][s], dp[i - 1][k] + p[j][i]);
其中s是当前i题时的状态,k是i-1题时的状态,而j就是当前要做的题,枚举j的值,j和k来更新s的值。

这里有一个初学者经常犯的错误,由于状态不能随意的转移(每次只有一个人做一道题目),所以要加入一些限制,设置dp数组为-1,表示不能访问的状态,这样在每次更新的时候,dp[i-1][k]就总是已经访问过的状态了。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<sstream>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#define INF 1<<27
#define eps 1e-9
#define LD long double
#define LL long long
#define CL(x,v); memset(x,v,sizeof(x));
const int maxn = 1005;
using namespace std;
double p[15][1005];// p[i][j] 表示 第i个同学答对第j个问题的概率
double dp[1005][1<<11];// dp[i][j]表示当前答到第i道题并且每个同学的做题状态为j时最大的总答对概率。
void solve(int n,int m)
{
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= (1 << n); j++) {
dp[i][j] = -1.0;
}
}
dp[0][0] = 0;
for (int i = 1; i <= m; i++)
{
for (int k = 0; k < (1 << n); k++)
{
if (dp[i-1][k] < 0)
continue;
for (int j = 1; j <= n; ++j)
{
if (k & 1 << (j - 1)) continue;
int s = k | 1 << (j - 1);//s表示下一个状态
if (s == (1 << n) - 1) s = 0;
dp[i][s] = max(dp[i][s], dp[i - 1][k] + p[j][i]);
}
}
}
}
int main()
{
#ifdef LOCAL
freopen("data.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif
int T;
scanf("%d",&T);
for (int kase = 1; kase <= T;++kase)
{
int n, m;
double ans = 0.0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n;++i)
for (int j = 1; j <= m; ++j)
{
scanf("%lf", &p[i][j]);
}
solve(n, m);
for (int i = 0; i <= (1 << n); i++)
{
ans = max(ans, dp[m][i]);
}
printf("Case #%d: %.5lf\n", kase, ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息