===基础===|【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; }

    推荐阅读