dp+一点概率分析 ---div2 -D

来源:互联网 发布:模拟考试软件 编辑:程序博客网 时间:2024/06/06 16:30

题意:有石头剪刀布i,j,k个 ,求某个最后统治小岛的概率

2016-5-9 回顾:
这道题,仔细想象不难发现,其实对于题目给定的东西和 要解答出的目标 都是一个个在不断变化的状态,
状态就是包含石头,剪刀,布的个数。我们只要把这些状态不停的变化,最后得到我们需要的状态就可以了。 这其实不正是dp的思想吗?

一道有点难度dp的题,贴一下思路
http://codeforces.com/contest/540/problem/D
那道题–好想看过,第一感觉
然后分析一波概率———不会
学习了一波
a b c 那么 a碰到b 的概率是(i * j)/ ( j*k+i *k + j *k) 其他同理,就不一一赘述。
i j k 个
当时画了个图
发现了几种状态转移:
(i,j,k) -> (i,j,k)+(i-1,j,k)+(i,j-1,k)+(i,j,k-1)
最后只要jk=0 就可以认为i成功了。
为什么我会觉得有一个i,j,k->i,j,k呢? 因为我当时认为,a是可以碰到a的,存在这种情况。
然后分析了一波,写出了一个状态转移方程。
发现不对~ 这样的状态转移我解不出来,因为包含了本身~ 不知道是不是有大牛能解出来。

后来重新找了一波状态转移方程:
去掉了第一种情况
p1 -> a碰到b 的情况 P2-> a碰到c的情况 p3-> b碰到c的情况
有: dp[i][j][k]= p1*dp[i][j-1][k] + p2*dp[i-1][j][k]+ p3*dp[i][j][k-1]
然而即便是状态转移方程写出来了,还是卡住了 囧
没有分析清楚每一种 由dp[i][j][k]转移的状态 的概率是+= ,直接写的= ,
因为dp[1][0][0] 可以由 dp[1][1][1] 先j- ,再由k-。 或者 先k-,然后再j-,两种都是可以到达的
又发现自己写错一个地方:
把p1,p2,p3写在了循环外面, 但是由于i,j,k在不停的变,所以p1,p2,p3也在不停地变 —-这真是一个傻×的错误,不多说了。
最后还是写出来了,最后对比了一下题解里面的代码,发现还是没有问题的。

#include<iostream>#include<stdio.h>#include<string.h>#include<math.h>#include<algorithm>#include<stdlib.h>#include<queue>#include<stack>#include<map>#include<vector>#define mem(a) memset(a,0,sizeof(a))#define pfn printf("\n")#define ll __int64#define pfd(a) printf("%d\n",a)#define pf2d(a,b) printf("%d %d\n",a,b)#define pf3d(a,b,c) printf("%d %d %d\n",a,b,c)#define pfs(a) printf("%s\n",a)#define sfd(a) scanf("%d",&a)#define sf2d(a,b) scanf("%d%d",&a,&b)#define sf3d(a,b,c) scanf("%d%d%d",&a,&b,&c)#define sfs(a) scanf("%s",a)#define sf  scanf#define pf  printf#define fr(i,n) for(int i=0;i<n;i++)#define INF 0x7fffffff   //INT_MAX#define inf 0x3f3f3f3f   //const double PI = acos(-1.0);const double e = exp(1.0);template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }template<class T> inline T Min(T a, T b) { return a < b ? a : b; }template<class T> inline T Max(T a, T b) { return a > b ? a : b; }bool cmpbig(int a,int b){return a>b;}bool cmpsmall(int a,int b){return a<b;}using namespace std;double dp[105][105][105];int main() {    freopen("1.txt","r",stdin);    int a,b,c;    while(~scanf("%d %d %d\n",&a,&b,&c)){        mem(dp);        double p1,p2,p3;        dp[a][b][c]=1;        for(int i=a;i>=0;i--)            for(int j=b;j>=0;j--)                for(int k=c;k>=0;k--){                    //  设开始状态为1 则                    if(i+j==0||i+k==0||j+k==0)                      continue;    //这个是不能少的,因为到了其他两个都为0的情况下,还去判断明显会错。                    p1= (i*j)*1.0/(i*j+i*k+j*k);   //a-b                    p2= (i*k)*1.0/(i*j+i*k+j*k);//a-c                    p3= (j*k)*1.0/(i*j+i*k+j*k);   //b-c                    if(j>0) dp[i][j-1][k]+=p1*dp[i][j][k];                    if(i>0) dp[i-1][j][k]+=p2*dp[i][j][k];                    if(k>0) dp[i][j][k-1]+=p3*dp[i][j][k];                }        double ans1=0,ans2=0,ans3=0;        for(int i=1;i<=a;i++)            ans1+=dp[i][0][0];        for(int i=1;i<=b;i++)            ans2+=dp[0][i][0];        for(int i=1;i<=c;i++)            ans3+=dp[0][0][i];        printf("%.12f %.12f %.12f\n",ans1,ans2,ans3);    }    return 0;}
0 0
原创粉丝点击