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
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;
else return 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;
else return 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;
}