【解题报告】编程之美初赛二 扑克牌
原题地址: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; }