ZOJ 3605 Find the Marble

转载自 http://blog.sina.com.cn/s/blog_5123df350100zp0s.html
照着题解写一次,就当自己懂了。
zoj 和virtual oj 都挂了。好像。。

n个罐子,有一个石头放在第s号罐子里,然后交换这些罐子m次,只能记住k次,每次交换被忘掉的概率相同,那个猜的人(按概率最大的猜)最可能猜哪号罐子里有石头。用dp[i][j][k]表示交换了i次,忘掉了j次,石头在k号罐子里的概率。知道dp[i-1][j][t]开始推,如果它忘掉了这次dp[i][j+1][t]+=dp[i-1][j][t]*p2。如果没忘掉这次,如果这次交换(x,y)有x==t,则dp[i][j][y]+=dp[i-1][j][t]*p1,同理如果y==t则dp[i][j][y]+=dp[i-1][j][t]*p1;否则的话dp[i][j][t]=dp[i-1][j][t]*p1。其中p1是没忘记的概率,p2是忘记的概率p1=k/m , p2=1-p1。 初始dp[0][0][s]=1。最终求argmax{dp[m][m-k][x]}。

#include<stdio.h>
#include<algorithm>
#include<string.h>

struct  sp
{
    int x,y;
}p[100];
double  dp[100][100][100];
int main()
{
//  freopen("F:\\123.txt","r",stdin);
        int t,m,n,k,s;
    scanf("%d",&t);
    for(int ik=1;ik<=t;ik++)
    {
       scanf("%d%d%d%d",&n,&m,&k,&s);
       for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&p[i].x ,&p[i].y );

        }
     memset(dp,0,sizeof(dp));
     double p1=(double)k/m,p2=(double)1-p1;

      // printf("%f %f\n",p1,p2);
       dp[0][0][s]=1;

       for(int i=1;i<=m;i++)
      {
         for(int j=0;j<=m-k &&j<=i;j++)
         {
            for(int u=1;u<=n;u++)
            {
               dp[i][j+1][u]+=dp[i-1][j][u] *p2;
         // printf("see %d %d\n",p[i].x ,u);
                if(p[i].x ==u )
                {
                   dp[i][j][p[i].y ]+=dp[i-1][j][u]*p1;
        //    printf("look %d %f\n",p[i].y ,dp[i][j][p[i].y ]);
                }else if(p[i].y ==u)
                 {
                    dp[i][j][p[i].x ]+=dp[i-1][j][u]*p1;
                 }
                 else
                 {
                     dp[i][j][u]+=dp[i-1][j][u];
        /* 题解一开始漏了说这种转移情况,然后我用codeblock演算过程,发现当    p[i].x ==u 和    p[i].y ==u 都不成立的时候,应该
        有       dp[i][j][u]+=dp[i-1][j][u]; 情况,即是看到了,但是交换的两个罐子都不含有硬币。。。即当前状态,需要继承i-1时的状态*/
                 }
            }
         }
      }
        int maxi=1;
        for(int i=1;i<=n;i++)
        {
        //  printf("%d %f\n",i,dp[m][m-k][i]);
            if(dp[m][m-k][i]>dp[m][m-k][maxi])
            {
                maxi=i;
            }
          }
          printf("%d\n",maxi);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值