UVa1637纸牌游戏(紫书327)

时间限制:1秒  内存限制:64M

【问题描述】

  有36张纸牌分成9堆,每堆4张。每次可以拿走某两堆顶部的牌,但需要点数相同。如果有有种拿法则等概率的随机拿。例如,9堆牌的顶部的那张分别是:KS、KH、KD、9H、8S、8D、7C、7D、6H,则有5种拿法(KS,KH)、(KS,KD)、(KH,KD)、(8S,8D)、(7S,7D),每种拿法的概率均为1/5。如果最后拿完所有牌则游戏成功。按时顺序给出每堆牌的4张牌,求成功概率。

【输入格式】

  输入数据包含若干组数据,每组数据包含9行,第i行表示第i堆从底部到顶部的每张牌。牌的表示用两个字符,第一个字符表示牌的数字:’1’~’9’,T表示10,J表示jack,Q' 表示 queen,K’表示 king, `A’ for ACE;第二个字符表示牌型:黑桃(S)、红心(H)、方块(D)、梅华(C)。例如:’KS’表示黑桃King。 spades.

【输出格式】

  对于每组数据输出一个实数,表示获胜概率,保留6为小数。

【输入样例】

AS 9S 6C KS
JC QH AC KH
7S QD JD KD
QS TS JS 9H
6D TD AD 8S
QC TH KC 8D
8C 9D TC 7C
9C 7H JH 7D
8H 6S AH 6H

【输出样例】

?
1
0.589314

【来源】

UVa1637纸牌游戏(紫书327)

一道很简单的题,直接用状态压缩(状态:9组牌分别有多少张)来个数组然后枚举情况递推就好,要注意的是如果有k种后继情况,每种情况增加的概率为当前情况概率除以k(比较是等概率随机)

仔细的人算一下会发现极限情况会超时。

但不仔细的人直接交就过了,我反正没有优化,比较难得想。

详细代码如下:

#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=1953125+5;

double d[maxn];
char a[9][10][5];
int b[10],tot;
void work1(int x)
{
    for(int i=1;i<=9;i++)
    b[i]=x%5,x/=5;
}
int work2()
{
    int x=0;
    for(int i=9;i>=1;i--)
    x=x*5+b[i];
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%s",a[1][1])==1)
    {
        memset(d,0,sizeof(d));
        for(int i=1;i<=9;i++)
        for(int j=1;j<=4;j++) if(i!=1||j!=1)
        scanf("%s",a[i][j]);
        int tt;
        d[1953124]=1.0;
        for(int i=1953124;i>=0;i--) if(d[i]>0)
        {
            work1(i);
            tot=0;
            for(int x=1;x<=9;x++) if(b[x]>0)
            for(int y=x+1;y<=9;y++)if(b[y]>0)
            if(a[x][b[x]][0]==a[y][b[y]][0])
            tot++;
            for(int x=1;x<=9;x++) if(b[x]>0)
            for(int y=x+1;y<=9;y++)if(b[y]>0)
            if(a[x][b[x]][0]==a[y][b[y]][0])
            {
                b[x]--;b[y]--;
                tt=work2();
                d[tt]+=d[i]/tot;
                b[x]++;b[y]++;
            }
        }
        printf("%.6lf",d[0]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值