配对游戏
时间限制:1秒
空间限制:262144K
美团点评是综合性生活服务平台,覆盖吃喝玩乐。在休闲娱乐版块,有很多轰趴、桌游、密室逃脱类的项目,适合多人一起玩。下面就是出自团队游戏场景中的一个问题。
有 n 个人排成一排,一开始全部面向前方,然后大家一起转身,随机朝左或是朝右转。
转身后,不断检查队列,如果存在两个面对面的相邻的人,则将这两个人从队列中消除;直到不存在两个面对面的相邻的人。
例如 > 表示向右, < 表示向左
队列“>>><<<”的消除过程为,“>>><<<”到“>><<”到“><”到“”(每次去除一对),最后剩下人数为0。
队列“>><><<<>”的消除过程为,“>><><<<>”到“>><<<>”到“><<>”到“<>”(每次去除一对),最后剩下人数为2
求最后剩下人数的期望值。
有 n 个人排成一排,一开始全部面向前方,然后大家一起转身,随机朝左或是朝右转。
转身后,不断检查队列,如果存在两个面对面的相邻的人,则将这两个人从队列中消除;直到不存在两个面对面的相邻的人。
例如 > 表示向右, < 表示向左
队列“>>><<<”的消除过程为,“>>><<<”到“>><<”到“><”到“”(每次去除一对),最后剩下人数为0。
队列“>><><<<>”的消除过程为,“>><><<<>”到“>><<<>”到“><<>”到“<>”(每次去除一对),最后剩下人数为2
求最后剩下人数的期望值。
输入描述:
一行一个正整数 n (1 ≤ n ≤ 2000)。
输出描述:
一行一个实数,表示剩下人数的期望值,四舍五入保留三位小数。
输入例子1:
10
输出例子1:
4.168
一开始思考了好久也没明白
这个转移方程中为什么g[i][j]不除以2,后来恍然大悟,因为我们在添上一个向左的人后,是一次性消去两个人,这里相当于 g[i][j] * 2 / 2 再加到期望消除人数上,也就等于g[i][j]。(g[i][j] * 2是因为消去两个人, / 2是因为只有一半的概率转移到这种状态(添加向左的人))
其他的转移还是蛮好明白的,还有就是注意j为0的时候即使添加上一个向左的人也没法消去。
这里推荐另一个很好的解题思路,也很巧妙并且容易理解:点击打开链接
代码:
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
#define pi acos(-1)
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define rep(i,x,n) for(int i=x;i<n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
using namespace std;
typedef pair<int,int>P;
const int MAXN=100010;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
double f[2100][2100];
double g[2100][2100];
int main()
{
int n;
cin >> n;
g[0][0] = 1;
for(int i = 0; i <= n; i++)
{
for(int j = 0; j <= i; j++)
{
if(j)
{
g[i + 1][j + 1] += g[i][j] * 0.5;
g[i + 1][j - 1] += g[i][j] * 0.5;
f[i + 1][j + 1] += f[i][j] * 0.5;
f[i + 1][j - 1] += f[i][j] * 0.5 + g[i][j] * 2 * 0.5;
}
else
{
g[i + 1][j + 1] += g[i][j] * 0.5;
g[i + 1][j] += g[i][j] * 0.5;
f[i + 1][j + 1] += f[i][j] * 0.5;
f[i + 1][j] += f[i][j] * 0.5;
}
}
}
double ans = n;
for(int i = 0; i <= n; i++)
{
ans -= f[n][i];
}
cout << fixed << setprecision(3) << ans << endl;
return 0;
}