===基础===|【NOIP2015】斗地主
4610 斗地主
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 大师 Master
题解
题目描述 Description
牛牛最近迷上了一种叫斗地主的扑克游戏。 斗地主是一种使用黑桃、红心、梅花、方片的 A 到 K 加上大小王的共 54 张牌来进行的扑克牌游戏。
在斗地主中, 牌的大小关系根据牌的数码表示如下: 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K < A < 2 < 小王 < 大王, 而花色并不
对牌的大小产生影响。 每一局游戏中,一副手牌由 n 张牌组成。游戏者每次可以根据规
定的牌型进行出牌, 首先打光自己的手牌一方取得游戏的胜利。
现在,牛牛只想知道,对于自己的若干组手牌, 分别最少需要多少次出牌可以将它
们打光。 请你帮他解决这个问题。
需要注意的是, 本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。
具体规则如下:
输入描述 Input Description
输入文件名为 landlords.in。
第一行包含用空格隔开的 2 个正整数T,n,表示手牌的组数以及每组手牌的张数。
接下来T组数据,每组数据n行, 每行一个非负整数ai,bi,对表示一张牌, 其中ai表
示牌的数码,bi表示牌的花色,中间用空格隔开。 特别的, 我们用1 来表示数码 A, 11 表
示数码 J, 12 表示数码 Q, 13 表示数码 K;黑桃、红心、梅花、方片分别用 1-4 来表示; 小
王的表示方法为 0 1, 大王的表示方法为 0 2。
输出描述 Output Description
输出文件名为 landlords.out。
共 T 行,每行一个整数,表示打光第i组手牌的最少次数。
样例输入 Sample Input
输入样例1
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
—————
输入样例2
1 17
12 3
4 3
2 3
5 4
10 2
3 3
12 2
0 1
1 3
10 1
6 2
12 1
11 3
5 2
12 4
2 2
7 2
样例输出 Sample Output
输出样例1
【===基础===|【NOIP2015】斗地主】3
—————
输出样例2
6
首先,花色没用
其次,牌的顺序与答案无关
搜索,找到暴力先出三带一四带一们
再开始找
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int MAXN = 40;
int t,n,x,ans = 1e9;
int use[20],sl[MAXN],num[MAXN];
int check(){
memset(sl,0,sizeof(sl));
int tot = 0;
for(int i = 0;
i <= 13;
i ++)sl[use[i]] ++;
while(sl[4] && sl[2] >= 2)//4 dai 2
sl[4] --,sl[2] -= 2,tot ++;
while(sl[4] && sl[1] >= 2)//4 dai 2
sl[4] --,sl[1] -= 2,tot ++;
while(sl[4] && sl[2])//4 dai 2
sl[4] --,sl[2] --,tot ++;
while(sl[3] && sl[2])//3 dai 2
sl[3] --,sl[2] --,tot ++;
while(sl[3] && sl[1]) //3 dai 1
sl[3] --,sl[1] --,tot ++;
int tot2 = sl[1] + sl[2] + sl[3] + sl[4];
tot += tot2;
return tot;
}
bool cmp(int a,int b){return a > b;
}
void work(int step){
if(step >= ans) return;
int ans1 = check();
if(ans1 + step < ans)
ans = ans1 + step;
int j = 2;
for(int i = 2;
i <= 13;
i ++){
j = i;
while(use[j] >= 3)j ++;
if(j - i >= 2){//san shun zi
for(int k = i + 1;
k <= j - 1;
k ++){
for(int l = i;
l <= k;
l ++) use[l] -= 3;
work(step + 1);
for(int l = i;
l <= k;
l ++) use[l] += 3;
}
}
}
j = 2;
for(int i = 2;
i <= 13;
i ++){
j = i;
while(use[j] >= 2) j ++;
if(j - i >= 3){//shuang shun zi
for(int k = i + 2;
k <= j - 1;
k ++){
for(int l = i;
l <= k;
l ++) use[l] -= 2;
work(step + 1);
for(int l = i;
l <= k;
l ++) use[l] += 2;
}
}
}
j = 2;
for(int i = 2;
i <= 13;
i ++){
j = i;
while(use[j] >= 1) j ++;
if(j - i >= 5){//dan shun zi
for(int k = i + 4;
k <= j - 1;
k ++){
for(int l = i;
l <= k;
l ++) use[l] --;
work(step + 1);
for(int l = i;
l <= k;
l ++) use[l] ++;
}
}
}
}int work2(){
if(num[1]== num[2] ) return 1;
elsereturn 2;
}int work3(){
if(num[1]== num[2]&& num[2]== num[3] )return 1;
else if(num[1]== num[2]|| num[2]== num[3]|| num[1]== num[3] ) return 2;
else return 3;
}int work4(){
//if(num[1]== num[2]&& num[2]== num[3]&& num[3]== num[4] ) return 1;
memset(use,0,sizeof(use));
for(int i = 1;
i <= 4;
i ++) use[num[i] ] ++;
sort(use,use + 17,cmp);
if(use[0] == 4) return 1;
if(use[0] == 3) return 1;
if(use[0] == 2 && use[1] == 2)return 2;
if(use[0] == 2 && use[1] == 1 && use[2] == 1) return 3;
elsereturn 4;
}int main(){
freopen("landlords.in","r",stdin);
freopen("landlords.out","w",stdout);
scanf("%d %d",&t,&n);
while(t --){
memset(num,0,sizeof(num));
memset(use,0,sizeof(use));
memset(sl,0,sizeof(sl));
for(int i = 1;
i <= n;
i ++){
scanf("%d %d",&num[i] ,&x);
if(num[i]== 1) num[i]= 13;
//else if(num[i]== 2) num[i]= 14;
//else if(num[i]== 0) num[i]= 15;
else if(num[i] > 0) num[i]--;
use[num[i] ] ++;
}
if(n == 2)printf("%d\n",work2());
else if(n == 3)printf("%d\n",work3());
else if(n == 4)printf("%d\n",work4());
else{
ans = 1e9,work(0);
printf("%d\n",ans);
}
}
fclose(stdin);
fclose(stdout);
return 0;
}
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长