斗地主
程序员文章站
2022-06-12 13:38:29
...
- 当初看到这道题,我就有点懵,这个题目这么长,除了直接强行搜索想不出任何办法,那就搜吧,结果没想到就这样过了
- 其实思路比较简单:
- ①花色不影响大小,那么花色可以不管
- ②我们可以发现只有顺子中会出现2点和大小王,那么我们在搜索时就可以先不管顺子,先把其他的解决
- ③顺子因为较长可以作为后续优化处理,当发现还剩牌时步数已经比答案多,则返回
下面是代码:
//landlords
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int t,n,ans;
int a[25],c[25];
int rest(){
memset(c,0,sizeof(c));
for(int i=0;i<=13;i++)c[a[i]]++;
int tot=0;
while(c[4]&&c[2]>1){ //4带2带2
c[4]--;
c[2]-=2;
tot++;
}
while(c[4]&&c[1]>1){ //4带1带1
c[4]--;
c[1]-=2;
tot++;
}
while(c[4]&&c[2]){ //4带2
c[4]--;
c[2]--;
tot++;
}
while(c[3]&&c[2]){ //3带2
c[3]--;
c[2]--;
tot++;
}
while(c[3]&&c[1]){ //3带1
c[3]--;
c[1]--;
tot++;
}
return tot+c[1]+c[2]+c[3]+c[4]; //剩下没有出完的只能单出
}
void dfs(int now){
if(now>=ans) return;
int tmp=rest();
if(now+tmp<ans)
ans=now+tmp;
for(int i=2;i<=13;i++){ //3顺子
int j=i;
while(a[j]>=3) j++;
if(j-i>=2){
for(int k=i+1;k<=j-1;k++){
for(int l=i;l<=k;l++)
a[l]-=3;
dfs(now+1);
for(int l=i;l<=k;l++)
a[l]+=3;
}
}
}
for(int i=2;i<=13;i++){ //双顺子
int j=i;
while(a[j]>=2) j++;
if(j-i>=3){
for(int k=i+2;k<=j-1;k++){
for(int l=i;l<=k;l++)
a[l]-=2;
dfs(now+1);
for(int l=i;l<=k;l++)
a[l]+=2;
}
}
}
for(int i=2;i<=13;i++){ //单顺子
int j=i;
while(a[j]>=1) j++;
if(j-i>=5){
for(int k=i+4;k<=j-1;k++){
for(int l=i;l<=k;l++)
a[l]-=1;
dfs(now+1);
for(int l=i;l<=k;l++)
a[l]+=1;
}
}
}
}
int main()
{
// freopen("landlords.in","r",stdin);
// freopen("landlords.out","w",stdout);
scanf("%d%d",&t,&n);
while(t--){
memset(a,0,sizeof(a));
int x,y;
for(int i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if(x==1) x=13; //处理A点,只要保证大小顺序即可
else if(x) x--;
a[x]++;
}
ans=1e9;
dfs(0);
printf("%d\n",ans);
}
return 0;
}