您的位置:首页 > 其它

ZOJ-3711-Give Me Your Hand【概率dp】【10th浙江省赛】【好题】

2017-04-02 19:23 441 查看
BellyWhite and MightyHorse are two students of Marjar University. They are best friends and also roommates living in the same dorm. There are K students living in that dorm, including BellyWhite and MightyHorse.

BellyWhite posted a strange microblog in 2012-9-3:



This is quite strange. It means that BellyWhite will chop some “hands” into pieces if he’s been found playing games or some other activities which is not relevant to his research. This logic is insane, isn’t it?

We could call those things which are not relevant to BellyWhite’s research “bad things”. Now we know that BellyWhite will start doing bad things when he’s in the dorm for T minutes, and he will stop doing those things when he’s being warned by MightyHorse or leaving the dorm. If he’s been warned to stop doing bad things and then he stays in the dorm for another T minutes, he will start doing bad things again.

MightyHorse noticed the strange microblog BellyWhite posted, but he’s a good roommate, so he must took the risk of losing his “hands” to warn BellyWhite that he was doing something harmful to his research progress or even his PhD degree. Fortunately, MightyHorse has M plastic toy “hands”, so BellyWhite will only chop those toy hands into pieces when he’s being warned.

Here comes the problem. We only know that no one is in the dorm initially, and we heard N door open and close sounds, which means there are N people entered or exited the dorm. We logged exact time of all door sounds, but we don’t know who made the sound, that means all K students living in the dorm have the same possibility to enter / exit. We’d like to know the expected number of toy hands MightyHorse will have after 24 hours (1440 minutes).

Please note that using toy hand to stop BellyWhite from doing bad things take no time, which means that even at the moment MightyHorse or BellyWhite enter / exit the dorm, a toy hand will be used to stop the bad thing. But if that there’s no toy hand left, MightyHorse will not able to stop BellyWhite from doing bad things.

Input

There are multiple test cases. The first line of input is an integer Casenum indicating the number of test cases.

For each test case, the first line contains 4 integers T (1 ≤ T ≤ 100), N (1 ≤ N ≤ 100), M (1 ≤ M ≤ 100) and K (2 ≤ K ≤ 8) which are defined in descriptions above.

The following line contains N integers. For every integer ti(0 ≤ ti ≤ 1440, 0 ≤ i < N), it means that a student entered or exited the dorm at time ti.

We guarantee that all those N ti will be given in strictly increasing order.

Output

For each test case, output the expected number of toy hands that MightyHorse still have at time 1440, rounded to 6 decimal points.

Sample Input

2

60 2 10 2

200 260

100 2 8 5

1340 1341

Sample Output

5.000000

7.960000

题目链接:ZOJ-3711

题目大意:一个寝室有k个人(包括A和B),A要做坏事,B能组织A做坏事(最多阻止M次),问阻止次数的期望。

A开始做坏事的条件:在寝室连续呆T分钟,则开始做坏事

A停止做坏事的条件:离开寝室,或者,被B阻止

ps:如果A被B阻止之后又在寝室呆了T分钟,他会重新开始做坏事

已知:门被开关了M次,我们不知道是谁进来或出去

题目思路:

dp[i][j][k][l]

i:第i次开关门
j:房内人物状态(0: a,b都不在; 1: b在; 2: a在; 3: a,b都在)
k:表示a已经在房内连续呆了k分钟
l:表示剩余阻止次数


以下是代码:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <functional>
#include <numeric>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#include <deque>
#include <list>
using namespace std;

double dp[105][4][105][105];
//1.第几次进出
//2.a,b是否在房间里
//3.a被b警告后又在房间里呆了多久
//4.剩下几个toy
int main()
{
int _;
cin >> _;
while(_--)
{
int t,n,m,k;
cin >> t >> n >> m >> k;
int pre = 0,num = 0;
memset(dp, 0, sizeof dp);
dp[0][0][0][m] = 1.0;
for (int i = 1; i <= n; i++)
{
cin >> num;
int pot = num - pre;
pre = num;

//1.初始房间没有a,b

for (int j = 0; j <= m; j++)
{
dp[i][0][0][j] += dp[i - 1][0][0][j] * (k - 2) * 1.0 / k;  //进出的是其他人
dp[i][1][0][j] += dp[i - 1][0][0][j] * 1.0 / k;  //进来的是b这个人
dp[i][2][0][j] += dp[i - 1][0][0][j] * 1.0 / k;  //进来的是a这个人
}

//2.初始房间里面有b

for (int j = 0; j <= m; j++)
{
dp[i][0][0][j] += dp[i - 1][1][0][j] * 1.0 / k; //b出去了
dp[i][1][0][j] += dp[i - 1][1][0][j] * (k - 2) * 1.0 / k; //进出的是其他人
dp[i][3][0][j] += dp[i - 1][1][0][j] * 1.0 / k; //进来的是a
}

//3.初始房间里面有a

for (int l = 0; l <= t; l++)  //a在房间里面呆了多少时间
{
for (int j = 0; j <= m; j++)
{
dp[i][0][0][j] += dp[i - 1][2][l][j] * 1.0 / k;  //a出去了
dp[i][2][min(l + pot,t)][j] += dp[i - 1][2][l][j] * (k - 2) * 1.0 / k;  //进出的是其他人

//进来的是b
if (l + pot >= t)  //如果a做坏事的时间超过了t
{
dp[i][3][0][max(0, j - 1)] += dp[i - 1][2][l][j] * 1.0 / k;
}
else
{
dp[i][3][l + pot][j] += dp[i - 1][2][l][j] * 1.0 / k;
}

}
}

//4.初始房间里面有a和b
for(int l = 0; l <= t; l++) //a在房间里面呆了多少时间
{
for (int j = 0; j <= m; j++)
{
//在房间里面的时候警告过a(pot/t)次
dp[i][1][0][max(0, j - ((pot + l)/t))] += dp[i - 1][3][l][j] * 1.0 / k;  //a出去了
dp[i][2][(pot + l) % t][max(0, j - ((pot + l)/t))] += dp[i - 1][3][l][j] * 1.0 / k; //b出去了
dp[i][3][(pot + l) % t][max(0, j - ((pot + l)/t))] += dp[i - 1][3][l][j] * (k - 2) / k;
}
}
}

//计算答案

double ans = 0;
int pot = 1440 - pre;
for (int i = 0; i < 4; i++) //遍历a,b是否在房间
{
for (int l = 0; l <= t; l++)
{
for (int j = 0; j <= m; j++)
{
if (i < 3) ans += dp
[i][l][j] * j;
else ans += dp
[i][l][j] * max(0, j - ((pot + l)/t));
}
}
}
printf("%.6f\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp 概率dp zoj