您的位置:首页 > 其它

洛谷P2668 斗地主 [NOIP2015]

2016-08-16 23:33 375 查看

 

题目描述

牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。

现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。

需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。

具体规则如下:

/*by SilverN*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int mxn=20;
int T;
int n;
int cnt[mxn];
int ans;
int tot=0;
void dfs(int time){
tot++;
if(tot>9000000)return;
if(time>=ans)return;
int i,j;
bool flag=0;
for(i=0;i<=13;i++)
if(cnt[i]){flag=1;break;}
if(!flag){ans=time;return;}
//三顺子
for(i=1;i<=11;i++){
if(cnt[i]<3)continue;
int ed=i;
while(ed<13){
if(cnt[ed]<3)break;
cnt[ed++]-=3;
if(ed-i<2)continue;
dfs(time+1);
}
for(j=i;j<ed;j++)cnt[j]+=3;
}
//双顺子
for(i=1;i<=10;i++){
if(cnt[i]<2)continue;
int ed=i;
while(ed<13){
if(cnt[ed]<2)break;
cnt[ed++]-=2;
if(ed-i<3)continue;
dfs(time+1);
}
for(j=i;j<ed;j++)cnt[j]+=2;
}
//单顺子
for(i=1;i<=8;i++){
if(!cnt[i])continue;
int ed=i;
while(ed<13){
if(!cnt[ed])break;
cnt[ed++]--;
if(ed-i<5)continue;
dfs(time+1);
}
for(j=i;j<ed;j++)cnt[j]++;
}
//四带
for(i=1;i<=13;i++)
if(cnt[i]>=4){
cnt[i]-=4;
for(j=0;j<=13;j++){
if(i==j)continue;
if(cnt[j]>=2){
cnt[j]-=2;
dfs(time+1);
cnt[j]+=2;
}
}
cnt[i]+=4;
}

//三带
for(i=1;i<=13;i++)
if(cnt[i]>=3){
cnt[i]-=3;
for(j=0;j<=n;j++)
if(i!=j)
for(int k=1;k<=2;k++){
if(cnt[j]>=k){
cnt[j]-=k;
dfs(time+1);
cnt[j]+=k;
}
}
cnt[i]+=3;
}
//火箭 /对子 /炸弹 /单张
for(j=4;j;j--)
for(i=0;i<=13;i++)
if(cnt[i]>=j){
cnt[i]-=j;
dfs(time+1);
cnt[i]+=j;
}
return;
}
int main(){
scanf("%d%d",&T,&n);
int i,j;
while(T--){
memset(cnt,0,sizeof cnt);
ans=n;
for(i=1;i<=n;i++){
int a;
scanf("%d%*d",&a);
if(a==1)a=12;
else if(a==2)a=13;
else a-=2;
cnt[a]++;
}
dfs(0);
printf("%d\n",ans);
}
return 0;
}
View Code 敲了个暴搜果断WAWAWA

 

然后默默抄了题解

/*by SilverN*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int mxn=30;
int cnt[mxn],r[mxn];
int ans;
int T,n;
int query(){//r存储剩余[i]张的牌的数量
int tot=0;
memset(r,0,sizeof r);
for(int i=0;i<=13;i++)
r[cnt[i]]++;
while(r[4] && r[2]>=2)r[4]--,r[2]-=2,tot++;
while(r[4] && r[1]>=2)r[4]--,r[1]-=2,tot++;
while(r[4] && r[2])r[4]--,r[2]--,tot++;
while(r[3] && r[2])r[3]--,r[2]--,tot++;
while(r[3] && r[1])r[3]--,r[1]--,tot++;
return tot+r[1]+r[2]+r[3]+r[4];
}
void dfs(int time){
if(time>=ans) return;
int tmp=query();
if(time+tmp<ans)ans=tmp+time;
int i,j,x;
for(i=3;i;i--)
for(j=2;j<=13;j++){
x=j;
while(cnt[x]>=i){
x++;
if((i==3 && x-j>=2)||(i==2 && x-j>=3)||(i==1 && x-j>=5)){
for(int k=j;k<x;k++) cnt[k]-=i;
dfs(time+1);
for(int k=j;k<x;k++) cnt[k]+=i;
}
}
}
}
int main(){
scanf("%d%d",&T,&n);
int i,j;
while(T--){
memset(cnt,0,sizeof cnt);
ans=n;
for(i=1;i<=n;i++){
int a;
scanf("%d%*d",&a);
if(a==1)a=13;
else if(a)a--;
cnt[a]++;
}
dfs(0);
printf("%d\n",ans);
}
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: