【HDU】 4089 Activation 概率DP

2024-09-05 15:48
文章标签 dp 概率 hdu activation 4089

本文主要是介绍【HDU】 4089 Activation 概率DP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目大意:Tomato要玩一个游戏,他需要排队,一开始这个队列共有N个人,而他在队列的第M个位置,每当有玩家尝试激活登陆游戏时, 会概率性触发四个事件。p1的概率注册失败,队列无变化。p2的概率连接失败,排在队首的人排到队尾。p3的概率成功,队首出队。p4的概率服务器 瘫痪,停止激活!这时候如果排在Tomato前面的人不足K个,那么他会很气愤。问 : Tomato排在第k位以内服务器瘫痪的概率。

令dp[i][j]为一共有i个人的队列Tomato排在第j位服务器瘫痪的概率,通过采用逆推,那么我们可以得到一组状态转移方程:

i == 1 : dp[1][1] = dp[1][1] * p1 + dp[1][1] * p2 + p4;

i  >  1 :

2 <= j <= k : dp[i][j] = dp[i][j] * p1 + dp[i][j - 1] * p2 + dp[i - 1][j - 1] * p3 + p4;//前面不足K个人,Tomato愤怒

k + 1 <= j <= i : dp[i][j] = dp[i][j] * p1 + dp[i][j - 1] * p2 + dp[i - 1][j - 1] * p3;

(这里k可能大于i,我们暂且不管,在下面我们再来消去这里的副作用)

令pp = p2 / (1 - p1) , pp3 = p3 / (1 - p1) , pp4 = p4 / (1 - p1);

令:

i == 1 c[1] = pp4;

2 <= j <= k : c[j] = dp[i - 1][j - 1] * pp3 + pp4;

k + 1 <= j <= i : c[j] = dp[i - 1][j - 1] * pp3;

消去k>i的情况:1 <= j <= i : c[j] = dp[i - 1][j - 1] * pp3 + (j <= k ? pp4 : 0);(这里我们默认dp[0][j]已经初始化)

进而化简得到:

j == 1 : dp[i][1] = dp[i][i] * p + c[1]; (1)

2 <= j <= i : dp[i][j] = dp[i][j - 1] * pp2 + c[j];

由递推关系可知 :dp[i][i] = dp[i][1] * p ^ (i - 1) + tmp;   (2)

其中tmp = c[1] ^ (i - 1) + c[2] ^ (i - 2) + ... + c[i - 1];

联立(1)、(2) 消去dp[i][1]得 : dp[i][i] = tmp / (1 - p ^ i); (也可以消去dp[i][i])

回代得原式     :2 <= j <  i:    dp[i][j] = dp[i][j - 1] * p + c[j];

最终解即为dp[n][m]。


代码如下:


//HDU 4089 Activation 概率DP
/*p = p2 / (1 - p1)p31 = p3 / (1 - p1)p41 = p4 / (1 - p1)i = 1:           c[1] = pp4, dp[1][1] = pp4 / (1 - p)j == 1:c[1] = pp4;2 <= j <= k:c[j] = dp[i - 1][j - 1] * pp3 + pp4;(1)k + 1 <= j <= i:c[j] = dp[i - 1][j - 1] * pp3;      (2)联立(1)、(2) 得:2 <= j <= i:    c[j] = dp[i - 1][j - 1] * pp3 + (i <= k ? pp4 : 0);易知:j == 1:dp[i][1] = dp[i][i] * p + c[1];     (3)2 <= j <= k:dp[i][j] = dp[i][j - 1] * p + c[j]; (4)k + 1 <= j <= i:dp[i][j] = dp[i][j - 1] * p + c[j]; (5)联立(4)、(5) 得:2 <= j <= i:    dp[i][j] = dp[i][j - 1] * p + c[j];由递推关系可知 :dp[i][i] = dp[i][1] * pow(p, i - 1) + tmp;   (6)其中tmp = c[1] ^ (i - 1) + c[2] ^ (i - 2) + ... + c[i - 1];联立(3)、(6) 得:dp[i][i] = tmp / (1 - pow(p, i));回代得原式     :2 <= j <  i:    dp[i][j] = dp[i][j - 1] * p + c[j];最终解即为dp[n][m];
*/#include <stdio.h>
#include <string.h>
#define REP(i, a, b) for(int i = a; i <= b; ++i)
const double eps = 1e-5;
const int O = 2005;
double pp[O], dp[O][O], c[O], p1, p2, p3, p4, p, pp3, pp4;
int n, m, k;
void work(){if(1 - p1 - p2 < eps){//特判除数等于0的情况printf("%.5f\n", 0);return;}if(p4 < eps){//如果已经小于0.00001则直接输出0.00000printf("%.5f\n", 0);return;}p = p2 / (1 - p1);pp3 = p3 / (1 - p1);pp4 = p4 / (1 - p1);pp[0] = 1.0;REP(i, 0, n) dp[0][i] = dp[i][i] = 0;REP(i, 1, n) pp[i] = p * pp[i - 1];dp[1][1] = p4 / (1 - p1 - p2);REP(i, 2, n){REP(j, 1, i) c[j] = dp[i - 1][j - 1] * pp3 + (j <= k ? pp4 : 0);REP(j, 1, i) dp[i][i] += c[j] * pp[i - j];dp[i][i] /= (1 - pp[i]);dp[i][1] = dp[i][i] * p + c[1];REP(j, 2, i - 1) dp[i][j] = dp[i][j - 1] * p + c[j];}printf("%.5f\n", dp[n][m]);
}
int main(){while(~scanf("%d%d%d%lf%lf%lf%lf", &n, &m, &k, &p1, &p2, &p3, &p4)) work();return 0;
}


 

这篇关于【HDU】 4089 Activation 概率DP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139388

相关文章

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while