您的位置:首页 > 编程语言

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

2015-05-05 21:36 127 查看
原题地址: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;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: