Double Patience - POJ 2794 状压dp

Double Patience
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 609 Accepted: 326
Case Time Limit: 1000MS Special Judge

Description

Double Patience is a single player game played with a standard 36-card deck. The cards are shuffled and laid down on a table in 9 piles of 4 cards each, faces up. 

After the cards are laid down, the player makes turns. In a turn he can take top cards of the same rank from any two piles and remove them. If there are several possibilities, the player can choose any one. If all the cards are removed from the table, the player wins the game, if some cards are still on the table and there are no valid moves, the player loses. 

George enjoys playing this patience. But when there are several possibilities to remove two cards, he doesn't know which one to choose. George doesn't want to think much, so in such case he just chooses a random pair from among the possible variants and removes it. George chooses among all possible pairswith equal probability. 

For example, if the top cards are KS, KH, KD, 9H, 8S, 8D, 7C, 7D, and 6H, he removes any particular pair of (KS, KH), (KS, KD), (KH, KD), (8S, 8D), and (7C, 7D) with the equal probability of 1/5. 

Once George's friend Andrew came to see him and noticed that he sometimes doesn't act optimally. George argued, that it is not important - the probability of winning any given patience with his strategyis large enough. 

Help George to prove his statement - given the cards on the table in the beginning of the game, find out what is the probability of George winning the game if he acts as described. 

Input

The input contains nine lines. Each line contains the description of four cards that form a pile in the beginning of the game, from the bottom card to the top one. 

Each card is described with two characters: one for rank, one for suit. Ranks are denoted as '6' for six, '7' for seven, '8' for eight, '9' for nine, 'T' for ten, 'J' for jack, 'Q' for queen, 'K' for king, and 'A' for ace. 

Suits are denoted as 'S' for spades, 'C' for clubs, 'D' for diamonds, and 'H' for hearts. For example, "KS" denotes the king of spades. 

Card descriptions are separated from each other by one space. 

Output

Output one real number - the probability that George wins the game if he plays randomly. Your answer must be accurate up to 10 -6.

Sample Input

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

Sample Output

0.589314

题意:有9组牌,每组4张,两张牌的大小一样时可以消掉,每次只能消掉最上面的牌,然后一个在玩的时候如果有多种消法,就会随机选择其中一种,问他将所有牌都消掉的几率是多少。

思路:典型的状压dp,需要用到滚动数组,然后直接模拟即可。

AC代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
map<ll,double> match;
int dp[2][1000000],pow5[12];
int card[10][5],num[10],p[10][20],f[200];
double ans;
char s[10];
void solve(int S,int to)
{
    int i,j,k,ret=0;
    ll S2;
    double m1=match[S],m2;
    for(i=1;i<=9;i++)
    {   k=S%pow5[i]/pow5[i-1];
        if(k>0)
          num[i]=card[i][k];
        else
          num[i]=0;
    }
    for(i=0;i<=9;i++)
       p[i][0]=0;
    for(i=1;i<=9;i++)
       if(num[i]>0)
       {
           p[num[i]][0]++;
           p[num[i]][p[num[i]][0]]=i;

       }
    for(i=1;i<=9;i++)
       ret+=p[i][0]*(p[i][0]-1)/2;
    for(i=1;i<=9;i++)
       for(j=1;j<=p[i][0];j++)
          for(k=j+1;k<=p[i][0];k++)
          {
              m2=m1/ret;
              S2=S-pow5[p[i][j]-1]-pow5[p[i][k]-1];
              if(S2<=0)
                ans+=m2;
              else
              {
                  if(match[S2]==0)
                  {
                      dp[to][0]++;
                      dp[to][dp[to][0]]=S2;
                      match[S2]=m2;
                  }
                  else
                     match[S2]+=m2;
              }
          }
}
int main()
{
    int i,j,k;
    pow5[0]=1;
    for(i=1;i<=10;i++)
       pow5[i]=pow5[i-1]*5;
    f['A']=1;f['6']=2;f['7']=3;f['8']=4;f['9']=5;f['T']=6;f['J']=7;f['Q']=8;f['K']=9;
    while(~scanf("%s",s))
    {
        card[1][1]=f[s[0]];
        for(j=2;j<=4;j++)
        {
            scanf("%s",s);
            card[1][j]=f[s[0]];
        }
        for(i=2;i<=9;i++)
           for(j=1;j<=4;j++)
           {
               scanf("%s",s);
               card[i][j]=f[s[0]];
           }
        match.clear();
        ans=0;
        dp[0][0]=1;dp[0][1]=pow5[9]-1;match[pow5[9]-1]=1;
        for(i=1;i<=20;i++)
        {
            if(i&1)
            {
                dp[1][0]=0;
                for(j=1;j<=dp[0][0];j++)
                   solve(dp[0][j],1);
            }
            else
            {
                dp[0][0]=0;
                for(j=1;j<=dp[1][0];j++)
                   solve(dp[1][j],0);
            }
        }
        printf("%.6f\n",ans);
    }
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值