1. 程式人生 > WINDOWS開發 >AcWing337 撲克牌(計數dp)

AcWing337 撲克牌(計數dp)

這道題可以看出與花色無關,甚至與數值無關,我們只需要記住前一個放的值和現在放的不一樣就行了

又因為這是一個計數問題,所以我們還要知道前一個值放了之後,有多少種會不符合答案,再算的時候就要去掉他們

因此我們設計狀態f[][][][][],表示一張牌,一對牌,三張牌,四張牌同色的個數,然後再列舉一維k表示上一個牌放了後,有多少牌跟他一樣的

這樣就可以進行記憶化搜尋。

考慮放 A 類
f[A−(k==0)][B][C][D][0]f[A−(k==0)][B][C][D][0]
考慮放 B 類
2∗(B−(k==1))∗f[A+1][B−1][C][D][1]2∗(B−(k==1))∗f[A+1][B−1][C][D][1]

考慮放 C 類
3∗(C−(k==2))∗f[A][B+1][C−1][C][D][2]3∗(C−(k==2))∗f[A][B+1][C−1][C][D][2]
考慮放 D 類
4∗(D−(k==3))∗f[A][B][C+1][D−1][C][D][3]

前面的係數是因為,多張同樣的牌沒有區別,但是各自放的次數要相加,所以要乘係數。

技術分享圖片
#include<iostream>
#include<string>
#include
<cstring> using namespace std; typedef unsigned long long ull; const int N=14; ull f[14][14][14][14][5]; int cnt[55]; int tot[55]; string s[55]; int sum=1; ull dfs(int a,int b,int c,int d,int k){ auto &x=f[a][b][c][d][k]; if(x!=-1) return x; ull ans=0; if(a) ans+=(a-(k==1
))*dfs(a-1,b,c,d,0); if(b) ans+=2*(b-(k==2))*dfs(a+1,b-1,1); if(c) ans+=3*(c-(k==3))*dfs(a,b+1,c-1,2); if(d) ans+=4*d*dfs(a,c+1,d-1,3); return x=ans; } int get(char a){ if(a==T) return 10; if(a==J) return 11; if(a==Q) return 12; if(a==K) return 13; if(a==A) return 1; return a-0; } int main(){ int t; cin>>t; memset(f,-1,sizeof f); for(int i=0;i<=4;i++) f[0][0][0][0][i]=1; while(t--){ int n; cin>>n; int i; memset(cnt,0,sizeof cnt); memset(tot,sizeof tot); for(i=1;i<=n;i++){ cin>>s[i]; cnt[get(s[i][0])]++; } for(i=1;i<=13;i++) tot[cnt[i]]++; printf("Case #%d: ",sum++); cout<<dfs(tot[1],tot[2],tot[3],tot[4],0)<<endl; } }
View Code

因為陣列是ull型別,取模其實就是溢位,所以不用管。