很是暴力的搜索,以致於我都不相信我能過。c++
方法是:暴力枚舉全部牌型,而後暴力判斷是否可行。spa
很是暴力:code
void dfs(int x,int l){ if(l==0){ flag=0; check(1,0,0,0,0); if(flag)ans++; return; } if(x>14)return; for(res i=0;i<=limit[x]&&i<=l;++i){ jiry[x]=i; dfs(x+1,l-i); } }
搜下來發現牌型數量不大於$3000000$,由於出題人良心的把3都去掉了,因此總牌型大量縮減。three
這裏須要用到一個性質,若是一幅飛機或順子能夠大於另一幅同類型的牌,那麼把他拆開來也能夠大於另一幅牌拆開來。it
判斷部分分兩部分,先暴力搜索搜出哪些牌要被拆出來變成三張牌或四張牌。class
由於雙方的總牌數都不會很大,因此直接搜只會帶一個常數。搜索
這裏要注意,只有當九條可憐出了三張牌或四張牌之後,xx網友才能出三張牌或四張牌,否則九條可憐將沒法出小於xx網友的牌型。方法
最後二者出的三張牌和四張牌數量必須相等,否則會有一副牌沒法有對應的牌。im
void check(int x,int one,int oneortwo,int three,int four){ if(x>14){ if(three||four)return; check(one,oneortwo); return; } if(jiry[x]>=4){ jiry[x]-=4; check(x+1,one+1,oneortwo,three,four+1); jiry[x]+=4; if(flag)return; } if(jiry[x]>=3){ jiry[x]-=3; check(x+1,one,oneortwo+1,three+1,four); jiry[x]+=3; if(flag)return; } if(xx[x]>=4&&four){ xx[x]-=4; check(x+1,one,oneortwo,three,four-1); xx[x]+=4; if(flag)return; } if(xx[x]>=3&&three){ xx[x]-=3; check(x+1,one,oneortwo,three-1,four); xx[x]+=3; if(flag)return; } check(x+1,one,oneortwo,three,four); }
而後再用貪心的方式判斷最後的散牌是否能夠。while
枚舉有多少的三張牌要帶一個,而後獲得有多少的一張牌和多少的兩張牌能夠被帶掉。
對於九條可憐的牌,去掉最大的牌。對於xx網友的牌,去掉最小的牌。要先用兩張牌來貪心,再用一張牌來貪心。
剩下的牌直接掃一遍,若是在前$i$種牌中xx網友的牌比九條可憐的要多,則當前牌錯誤。
void check(int one,int oneortwo){ for(res i=0;i<=oneortwo;i++){ memcpy(jirycpy,jiry,sizeof jiry); memcpy(xxcpy,xx,sizeof xx); res o=i+one*2,t=oneortwo-i; for(res j=1;j<=14;++j){ while(xxcpy[j]>=2&&t)xxcpy[j]-=2,t--; while(xxcpy[j]>=1&&o)xxcpy[j]-=1,o--; } if(o||t)continue; o=i+one,t=oneortwo-i; for(res j=14;j;--j){ while(jirycpy[j]>=2&&t)jirycpy[j]-=2,t--; while(jirycpy[j]>=1&&o)jirycpy[j]-=1,o--; } if(o||t)continue; flag=1; for(res j=1,now=0;j<=14;++j){ now-=xxcpy[j]; if(now<0){ flag=0; break; } now+=jirycpy[j]; } if(flag)return; } }
而後是完整代碼
#include<bits/stdc++.h> #define res register int using namespace std; char str[15]; int jiry[15],xx[15],limit[15]; int jirycpy[15],xxcpy[15]; int cl(char c){ if(c=='T')return 7; else if(c=='J')return 8; else if(c=='Q')return 9; else if(c=='K')return 10; else if(c=='A')return 11; else if(c=='2')return 12; else if(c=='w')return 13; else if(c=='W')return 14; else return c-'3'; } bool flag; int ans; void check(int one,int oneortwo){ for(res i=0;i<=oneortwo;i++){ memcpy(jirycpy,jiry,sizeof jiry); memcpy(xxcpy,xx,sizeof xx); res o=i+one*2,t=oneortwo-i; for(res j=1;j<=14;++j){ while(xxcpy[j]>=2&&t)xxcpy[j]-=2,t--; while(xxcpy[j]>=1&&o)xxcpy[j]-=1,o--; } if(o||t)continue; o=i+one,t=oneortwo-i; for(res j=14;j;--j){ while(jirycpy[j]>=2&&t)jirycpy[j]-=2,t--; while(jirycpy[j]>=1&&o)jirycpy[j]-=1,o--; } if(o||t)continue; flag=1; for(res j=1,now=0;j<=14;++j){ now-=xxcpy[j]; if(now<0){ flag=0; break; } now+=jirycpy[j]; } if(flag)return; } } void check(int x,int one,int oneortwo,int three,int four){ if(x>14){ if(three||four)return; check(one,oneortwo); return; } if(jiry[x]>=4){ jiry[x]-=4; check(x+1,one+1,oneortwo,three,four+1); jiry[x]+=4; if(flag)return; } if(jiry[x]>=3){ jiry[x]-=3; check(x+1,one,oneortwo+1,three+1,four); jiry[x]+=3; if(flag)return; } if(xx[x]>=4&&four){ xx[x]-=4; check(x+1,one,oneortwo,three,four-1); xx[x]+=4; if(flag)return; } if(xx[x]>=3&&three){ xx[x]-=3; check(x+1,one,oneortwo,three-1,four); xx[x]+=3; if(flag)return; } check(x+1,one,oneortwo,three,four); }; void dfs(int x,int l){ if(l==0){ flag=0; check(1,0,0,0,0); if(flag)ans++; return; } if(x>14)return; for(res i=0;i<=limit[x]&&i<=l;++i){ jiry[x]=i; dfs(x+1,l-i); } } int main(){ scanf("%s",str+1); int len=strlen(str+1); for(int i=1;i<=12;++i){ limit[i]=4; } limit[13]=limit[14]=1; memset(xx,0,sizeof xx); for(int i=1;i<=len;++i){ limit[cl(str[i])]--; xx[cl(str[i])]++; } ans=0; dfs(1,17); printf("%d\n",ans); }