很是暴力的搜索,以致于我都不相信我能过。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); }