第一篇博文献给NOIP2015斗地主。
这道题为NOIP2015第一天第三题。属于爆搜类,没有任何算法,就是模拟加爆搜。由于有不同种打法,dfs分为好几层,本着先大后小便于剪枝的原则,先出顺子,再带牌,最后散着出。
首先,花色对结果无影响,其次大小王对结果是否有贡献只看是否出现其中之一,出现结果+1即可,未出现就不必管了(吐槽一下题目描述,没说四带二不算俩王,但测试点中确实不带)。还有一点值得注意的是大小顺序,首先是2不算顺子,其次1比3~13都大,因此可以把大小统一减2,1、2改为12、13便于使用。
先预处理出各个数字(以下都为预处理后的数字)的个数,开始分层爆搜。先提前说明各个数组,la[]为各个数字还剩几个没打,num[i]为数量为i的同数字牌还有几个
第一至三层为顺子,它们可以搜索到自己,因为一套牌可以出现多个顺子,至于顺子的长度,从大到小进行枚举,原理见上然后将搜索完的目标再次指向自己,在函数最后向下一层搜索。
第四,五层为带,四层为四带二,要注意是四带二不是四带一,因为这个卡了55%,带对带单都可以,又因为可以同时出四带两个单和四带两个双,因此需要引入一个bool型变量确认该次搜索由哪里传下来,若为上层则四带双和四带单都单独搜索,四带双继续指向本层,bool改变,只搜四带单,三同理。
第五层就是处理散牌了,不解释。
最后膜拜?大犇,有一个剪枝,若到盖层走的步数以比当前最优解大,则直接返回,貌似省了不少时间。
本来就是搜索题,只能说这些了,其实主要还是代码能力和脑洞。
#include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> #include<cmath> using namespace std; int t,n,ans=0x7fffffff; int sum[14],la[14],num[5]; void dfs6(int js){ if(js>=ans)return; int jj=0; for(int i=4;i>=1;i--) jj+=num[i]; ans=min(ans,jj+js); return; } void dfs5(int js,bool pd){ //3 _ if(js>=ans)return; int nn[5]; memcpy(nn,num,sizeof(num)); if(!pd) { for(int i=num[3];i>=1;i--) { if(num[2]>=i) { memcpy(num,nn,sizeof(num)); num[3]-=i; num[2]-=i; dfs5(js+i,1); memcpy(num,nn,sizeof(num));//记得还原,否则判断num[]将会失误。下同。 } } } for(int i=num[3];i>=1;i--) { if(num[1]>=i) { memcpy(num,nn,sizeof(num)); num[3]-=i; num[1]-=i; dfs6(js+i); memcpy(num,nn,sizeof(num)); } } memcpy(num,nn,sizeof(nn)); dfs6(js); } void dfs4(int js,bool pd){ //4 2 if(js>=ans) return; int nn[5]; if(!pd) { memset(num,0,sizeof(num)); for(int i=1;i<=13;i++) num[la[i]]++; memcpy(nn,num,sizeof(num)); for(int i=num[4];i>=1;i--) { if(num[2]>=i*2) { memcpy(num,nn,sizeof(nn)); num[4]-=i; num[2]-=i*2; dfs4(js+i,1); memcpy(num,nn,sizeof(nn)); } } } if(pd) memcpy(nn,num,sizeof(num)); for(int i=num[4];i>=1;i--) { if(num[1]>=i*2) { memcpy(num,nn,sizeof(nn)); num[4]-=i; num[1]-=i*2; dfs5(js+i,0); memcpy(num,nn,sizeof(nn)); } } memcpy(num,nn,sizeof(nn)); dfs5(js,0); } void dfs3(int js){ //1s if(js>=ans) return; int ll[14]; memcpy(ll,la,sizeof(la)); for(int l=12;l>=5;l--) { for(int i=1;i<=12-l+1;i++) { bool yx=1; for(int j=i;j<=i+l-1;j++) { if(la[j]<1) { yx=0; break; } } if(yx) { memcpy(la,ll,sizeof(ll)); for(int j=i;j<=i+l-1;j++) { la[j]-=1; } dfs3(js+1); memcpy(la,ll,sizeof(ll)); } } } memcpy(la,ll,sizeof(ll)); dfs4(js,0); } void dfs2(int js){ //2s if(js>=ans) return; int ll[14]; memcpy(ll,la,sizeof(la)); for(int l=11;l>=3;l--) { for(int i=1;i<=12-l+1;i++) { bool yx=1; for(int j=i;j<=i+l-1;j++) { if(la[j]<2) { yx=0; break; } } if(yx) { memcpy(la,ll,sizeof(ll)); for(int j=i;j<=i+l-1;j++) { la[j]-=2; } dfs2(js+1); memcpy(la,ll,sizeof(ll)); } } } memcpy(la,ll,sizeof(ll)); dfs3(js); } void dfs1(int js){ //3s if(js>=ans) return; int ll[14]; memcpy(ll,la,sizeof(la)); for(int l=7;l>=2;l--) { for(int i=1;i<=12-l+1;i++) { bool yx=1; for(int j=i;j<=i+l-1;j++) { if(la[j]<3) { yx=0; break; } } if(yx) { memcpy(la,ll,sizeof(ll)); for(int j=i;j<=i+l-1;j++) { la[j]-=3; } dfs1(js+1); memcpy(la,ll,sizeof(ll)); } } } memcpy(la,ll,sizeof(ll)); dfs2(js); } int main(){ scanf("%d%d",&t,&n); while(t--) { memset(sum,0,sizeof(sum)); memset(la,0,sizeof(la)); memset(num,0,sizeof(num)); ans=0x7fffffff; int a,b,c,d; for(int i=1;i<=n;i++) { int xx,yy; scanf("%d%d",&xx,&yy); if(xx==1) xx=12; else if(xx==2) xx=13; else xx-=2; if(xx==-2) xx=0; sum[xx]++; } memcpy(la,sum,sizeof(sum)); dfs1(0); if(sum[0]) ans++; printf("%d\n",ans); } //while(1); return 0; }
时间: 2024-09-30 19:16:42