看起来很凶残的一道题,但其实还是比较好做的
找到对应的状态转移方程就好做了
我是用打表法一次把结果全打出来了
时间复杂度是O(10×10×100)
0ms代码及注释如下:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
double sum[110][11];
double dp[110][11][11];
/*dp[k][i][n]
*k表示给定的集合中有k+1个元素
*i表示当前字符排列以i结尾
*n表示字符串长度
*dp[n][k][i] = dp[n-1][k][i-1]+dp[n-1][k][i]+dp[n-1][k][i+1]
*0 <= i <= k
*/
int main(void) {
int n, k, i;
memset(sum, 0, sizeof(sum));
for(k=0; k<10; ++k) {
for(i=0; i<=k; ++i)
dp[1][k][i] = 100.0;
}
for(n=1; n<101; ++n) {
for(k=0; k<10; ++k) {
for(i=0; i<=k; ++i) {
if(i-1 >= 0)
dp[n][k][i] += dp[n-1][k][i-1];
if(i+1 <= k)
dp[n][k][i] += dp[n-1][k][i+1];
dp[n][k][i] += dp[n-1][k][i];
sum[n][k] += dp[n][k][i];
}
for(int j=0; j<n; ++j)
sum[n][k] /= k+1.0;
}
}
while(scanf("%d%d", &k, &n) != EOF) {
printf("%.5lf\n", sum[n][k]);
}
return 0;
}
但是在ppt上看了用滚动数组优化的做法
OTZ
代码如下:
#include <cstdio>
using namespace std;
int main(){
int k, n, i, t;
double f[12], tmp[12], ans;
while(scanf("%d%d", &k, &n) != EOF) {
//f[i]表示以i为最后一位的满足条件字符串的总数
for(i=0; i<=k; ++i)
f[i] = 100.0/(k+1.0);
for(t=2; t<=n; ++t) {//共循环n次
tmp[0] = (f[0]+f[1]) / (k+1.0);
for(i=1; i<=k-1; ++i)
tmp[i] = (f[i-1]+f[i]+f[i+1]) / (k+1.0);
tmp[k] = (f[k-1]+f[k]) / (k+1.0);
//滚动数组优化,上一状态用不到了
for(i=0; i<=k; ++i)
f[i] = tmp[i];
}
for(ans=0.0,i=0; i<=k; ++i)
ans+=f[i];
printf("%.5lf\n", ans);
}
return 0;
}