【解题报告】编程之美初赛二 扑克牌

原题地址:http://hihocoder.com/contest/msbop2015round2b/problem/1

本博客讲的是大数据的解法。
这题是使用动态规划解,定义状态:

struct node
{
        int z,a[4];
}
其中a[i]表示当前状态下数量是i+1张的点数的牌的个数。
如:样例中 6 AC AD AS JC JD KD
A有3张,J有2张,K有一张,则a[0]=1,a[1]=1,a[2]=1
若是 6 AC AD AS JC JD JS 则a[2]=2,其他是0。

依次取每一张牌组成序列,其中z表示前一张牌的点数现在有z+1张。(z=-1时表示现在是0张)
如对于6 AC AD AS JC JD JS这个例子,初始状态为{z=-1,a=[0,0,2,0]}
则第一张牌可以是6张的任意一张,取任意一张所造成的状态都是{z=2,a=[0,1,1,0]}

对于任意状态{z,a0,a1,a2,a3}可以转化为4种状态,分别是:

{-1,a0-1,a1,a2,a3}:这个状态实际上是a0种选择(如果z不是0的话),因此总和要将这个状态的结果乘a0。如果z是0,则只有a0-1种选择,因为不能选择和前一张牌一样的点数。
{0,a0+1,a1-1,a2,a3}:这个状态是a1*2种选择,因为每种点数的牌有两张。如果z是1,则是(a1-1)*2种选择。
{1,a0,a1+1,a2-1,a3}
{2,a0,a1,a2+1,a3-1}

所以状态转移方程为:

f{z,a0,a1,a2,a3}=f{-1,a0-1,a1,a2,a3}    *(z==0?a0:a0-1)*1
                        +f{0,a0+1,a1-1,a2,a3}*(z==1?a1:a1-1)*2
                        +f{1,a0,a1+1,a2-1,a3}*(z==2?a2:a2-1)*3
                        +f{2,a0,a1,a2+1,a3-1}*(z==3?a3:a3-1)*4

代码如下:(记忆化搜索写法)

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<map>
using namespace std;
typedef unsigned long long ll;
struct node
{
    int z,a[4];
    bool operator<(const node &no) const
    {
        if(z!=no.z) return z<no.z;
        for(int i=0;i<4;i++)
            if(a[i]!=no.a[i]) return a[i]<no.a[i];
    }
};
map<node,ll> M;
int num[100],n;
ll dfs(node no)
{
    if(M.count(no))
    {
        return M[no];
    }
    if(no.a[0]==0&&no.a[1]==0&&no.a[2]==0&&no.a[3]==0)
    {
        return 1;
    }
    ll ans=0;
    for(int i=0;i<4;i++)
    {
        if(no.a[i]!=0)
        {
            node no2;
            no2.z=i-1;
            no2.a[0]=no.a[0];
            no2.a[1]=no.a[1];
            no2.a[2]=no.a[2];
            no2.a[3]=no.a[3];
            no2.a[i]--;
            if(i!=0) no2.a[i-1]++;
            if(i==no.z)
            {
                ans+=(no.a[i]-1)*(i+1)*dfs(no2);
            }
            else
            {
                ans+=(no.a[i])*(i+1)*dfs(no2);
            }
        }
    }
    return M[no]=ans;
}
int main()
{
    int t,i,cas=1;
    char s[5];
    scanf("%d",&t);
    while(t--)
    {
        memset(num,0,sizeof(num));
        scanf("%d",&n);
        for(i=0;i<n;++i)
        {
            scanf("%s",s);
            if(s[0]>='2'&&s[0]<='9')
            {
                num[s[0]-'0']++;
            }
            else
            {
                if(s[0]=='A')
                {
                    num[1]++;
                }
                else if(s[0]=='T')
                {
                    num[10]++;
                }
                else if(s[0]=='J')
                {
                    num[11]++;
                }
                else if(s[0]=='Q')
                {
                    num[12]++;
                }
                else if(s[0]=='K')
                {
                    num[13]++;
                }
            }
        }
        node no;
        no.z=-1;
        memset(no.a,0,sizeof(no.a));
        for(i=1;i<=13;i++)
        {
            if(num[i]!=0) no.a[num[i]-1]++;
        }
        printf("Case #%d: %llu\n",cas++,dfs(no));
    }
    return 0;
}

  

posted on 2015-05-05 21:36  T^T  阅读(361)  评论(0编辑  收藏  举报

导航