洛谷 P2668 & P2540 [ noip 2015 ] 斗地主 —— 搜索+贪心
题目:https://www.luogu.org/problemnew/show/P2668
https://www.luogu.org/problemnew/show/P2540
首先,如果没有顺子,那么有贪心最优解;
所以先搜索顺子,再贪心求剩余的出牌方案;
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int T,n,a[15],t[15],ans,inf=0x3f3f3f3f; int calc() { int ret=0; memset(t,0,sizeof t); for(int i=0;i<=13;i++)t[a[i]]++; while(t[4]&&t[2]>=2)t[4]--,t[2]-=2,ret++; while(t[4]&&t[1]>=2)t[4]--,t[1]-=2,ret++; while(t[4]&&t[2])t[4]--,t[2]--,ret++; while(t[3]&&t[2])t[3]--,t[2]--,ret++; while(t[3]&&t[1])t[3]--,t[1]--,ret++; return ret+t[1]+t[2]+t[3]+t[4]; } void dfs(int u)//顺子 { if(u>ans)return; int tmp=calc(); if(u+tmp<ans)ans=u+tmp; for(int i=2,j;i<=13;i++) { for(j=i;j<=13;j++)if(a[j]<3)break; j--; if(j-i+1<2)continue; for(int k=j;k>=i+1;k--) { for(int l=i;l<=k;l++)a[l]-=3; dfs(u+1); for(int l=i;l<=k;l++)a[l]+=3; } } for(int i=2,j;i<=13;i++) { for(j=i;j<=13;j++)if(a[j]<2)break; j--; if(j-i+1<3)continue; for(int k=j;k>=i+2;k--) { for(int l=i;l<=k;l++)a[l]-=2; dfs(u+1); for(int l=i;l<=k;l++)a[l]+=2; } } for(int i=2,j;i<=13;i++) { for(j=i;j<=13;j++)if(!a[j])break; j--; if(j-i+1<5)continue; for(int k=j;k>=i+4;k--) { for(int l=i;l<=k;l++)a[l]--; dfs(u+1); for(int l=i;l<=k;l++)a[l]++; } } } int main() { scanf("%d%d",&T,&n); while(T--) { memset(a,0,sizeof a); for(int i=1,x,y;i<=n;i++) { scanf("%d%d",&x,&y); if(x==1)x=13; else if(x)x--; a[x]++; } ans=inf; dfs(0); printf("%d\n",ans); } return 0; }
增强版要考虑拆牌,看了题解,感觉好混乱...
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int T,n,a[15],t[15],ans,inf=0x3f3f3f3f; int calc() { int ret=0;bool wz=0; memset(t,0,sizeof t); if(a[0]==2)wz=1; t[1]+=a[0]; for(int i=1;i<=13;i++)t[a[i]]++; while(!t[3]&&t[4]>1&&t[1]==1&&t[2]==1)t[4]-=2,t[1]--,t[2]--,ret+=2;//4=3+1,出四带二单和三带二 while(!t[2]&&t[3]>1&&t[1]==1&&t[4]==1)t[3]-=2,t[1]--,t[4]--,ret+=2;//3=2+1,出四带二单和三带二 if(t[3]+t[4]>t[1]+t[2]) while(t[4]&&t[2]&&t[3])t[4]--,t[2]--,t[3]--,t[1]++,ret++;//3=2+1,出四带二对,余一单 if(t[3]+t[4]>t[1]+t[2]) while(t[4]&&t[1]&&t[3])t[4]--,t[1]--,t[3]--,t[2]++,ret++;//3=2+1,出四带二单,余一对 while(t[4]&&t[2]>1)t[4]--,t[2]-=2,ret++; while(t[4]&&t[1]>1)t[4]--,t[1]-=2,ret++; while(t[4]&&t[2])t[4]--,t[2]--,ret++; if(t[3]%3==0&&t[1]+t[2]<=1) while(t[3]>2)t[3]-=3,ret+=2;//3=2+1,出三带二,三带一 while(t[3]&&t[2])t[3]--,t[2]--,ret++; while(t[3]&&t[1])t[3]--,t[1]--,ret++; //还剩3和4 while(t[4]>1&&t[3])t[4]-=2,t[3]--,ret+=2;//4=2+2,出四带二和三带二 while(t[3]>1&&t[4])t[3]-=2,t[4]--,ret+=2;//4=2+2,出2*三带二 while(t[3]>2)t[3]-=3,ret+=2;//3=2+1,出三带二和三带一 while(t[4]>1)t[4]-=2,ret++;//4=2+2,出四带二对 if(wz&&t[1]>=2)return ret+t[4]+t[3]+t[2]+t[1]-1; else return ret+t[4]+t[3]+t[2]+t[1]; } void dfs(int u)//顺子 { if(u>ans)return; int tmp=calc(); if(u+tmp<ans)ans=u+tmp; for(int i=2,j;i<=13;i++) { for(j=i;j<=13;j++)if(a[j]<3)break; j--; if(j-i+1<2)continue; for(int k=j;k>=i+1;k--) { for(int l=i;l<=k;l++)a[l]-=3; dfs(u+1); for(int l=i;l<=k;l++)a[l]+=3; } } for(int i=2,j;i<=13;i++) { for(j=i;j<=13;j++)if(a[j]<2)break; j--; if(j-i+1<3)continue; for(int k=j;k>=i+2;k--) { for(int l=i;l<=k;l++)a[l]-=2; dfs(u+1); for(int l=i;l<=k;l++)a[l]+=2; } } for(int i=2,j;i<=13;i++) { for(j=i;j<=13;j++)if(!a[j])break; j--; if(j-i+1<5)continue; for(int k=j;k>=i+4;k--) { for(int l=i;l<=k;l++)a[l]--; dfs(u+1); for(int l=i;l<=k;l++)a[l]++; } } } int main() { scanf("%d%d",&T,&n); while(T--) { memset(a,0,sizeof a); for(int i=1,x,y;i<=n;i++) { scanf("%d%d",&x,&y); if(x==1)x=13; else if(x)x--; a[x]++; } ans=inf; dfs(0); printf("%d\n",ans); } return 0; }