[NOIP 2016TG D1T3] 斗地主

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOIP 2016TG D1T3] 斗地主相关的知识,希望对你有一定的参考价值。

题目描述

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

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

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

具体规则如下:

技术分享

输入输出格式

输入格式:

 

第一行包含用空格隔开的2个正整数T和n,表示手牌的组数以及每组手牌的张数。

接下来T组数据,每组数据n行,每行一个非负整数对aibi表示一张牌,其中ai示牌的数码,bi表示牌的花色,中间用空格隔开。特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大王的表示方法为02。

 

输出格式:

 

共T行,每行一个整数,表示打光第i手牌的最少次数。

 

输入输出样例

输入样例#1:
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
输出样例#1:
3
输入样例#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
输出样例#2:
6

说明

样例1说明

共有1组手牌,包含8张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方片A以及黑桃A。可以通过打单顺子(方片7,方片8,黑桃9,方片10,黑桃J),单张牌(黑桃5)以及对子牌(黑桃A以及方片A)在3次内打光。

对于不同的测试点, 我们约定手牌组数T与张数n的规模如下:

技术分享

数据保证:所有的手牌都是随机生成的。

一看时限2s内存1G就知道这道题一定很神。不过我最后还是秒过了。首先前6个点很水,贪心的想法,能出的都出掉好了。

然而。。。后面的点就mmp了。嗯。。。

肯定是DFS或DP,DP不敢写,那只好写DFS了,稳不类。。。

DFS呢还是贪心的套路,我们要用到“最优性剪枝”。小王大王都先放一边,先考虑顺子,顺子先把他出掉试试呗!事实证明,数据全随机的话,你先出顺子,找到较优解或最优解

可能很大。三顺子,双顺子,单顺子。顺子完了以后,就考虑几带几什么的了,没有了顺子,贪心的想法,这样的顺序:4带2,4带1,3带2,3带1,然后散牌。然后就不知不觉

了。时间很快。。。-_-

技术分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 using namespace std;
 6 int T,n;
 7 void poker_situ1(){
 8     int x,y;
 9     int big=0,sml=0,p[15];
10     memset(p,0,sizeof p);
11     for (int i=1; i<=n; i++){
12         scanf("%d%d",&x,&y);
13         if (x==0&&y==1) big++; else
14         if (x==0&&y==2) sml++; else{
15             if (x==2) p[13]++; else if (x==1) p[12]++; else p[x-2]++;
16         }
17     }
18     for (int i=1; i<=13; i++) if (p[i]==n){puts("1"); return;}
19     if (n==4) for (int i=1; i<=13; i++) if (p[i]==3){puts("1"); return;}
20     int ans;
21     if (big==1&&sml==1) ans=1; else if (big+sml==1) ans=1; else ans=0;
22     for (int i=1; i<=13; i++) if (p[i]==2) ans++;
23     for (int i=1; i<=13; i++) if (p[i]==1) ans++;
24     printf("%d\n",ans);
25 }
26 int big=0,sml=0,p[15],ans,cnt[5],tp[5];
27 void DFS(int stp,int crd,int pok[],int cot[]){
28     if (stp>=ans) return;
29     if (!crd){ans=stp; return;}
30     for (int i=12; i>=2; i--) if (pok[i]>=3){
31         int sto=1;
32         for (int j=i; j>=1; j--) if (pok[j]<3){sto=j+1; break;}else{
33             cot[pok[j]]--,pok[j]-=3,cot[pok[j]]++;
34             if (i-j+1>=2) DFS(stp+1,crd-3*(i-j+1),pok,cot);
35         }
36         for (int j=sto; j<=i; j++) cot[pok[j]]--,pok[j]+=3,cot[pok[j]]++;
37     }
38     for (int i=12; i>=3; i--) if (pok[i]>=2){
39         int sto=1;
40         for (int j=i; j>=1; j--) if (pok[j]<2){sto=j+1; break;}else{
41             cot[pok[j]]--,pok[j]-=2,cot[pok[j]]++;
42             if (i-j+1>=3) DFS(stp+1,crd-2*(i-j+1),pok,cot);
43         }
44         for (int j=sto; j<=i; j++) cot[pok[j]]--,pok[j]+=2,cot[pok[j]]++;
45     }
46     for (int i=12; i>=5; i--) if (pok[i]>=1){
47         int sto=1;
48         for (int j=i; j>=1; j--) if (pok[j]<1){sto=j+1; break;}else{
49             cot[pok[j]]--,pok[j]-=1,cot[pok[j]]++;
50             if (i-j+1>=5) DFS(stp+1,crd-1*(i-j+1),pok,cot);
51         }
52         for (int j=sto; j<=i; j++) cot[pok[j]]--,pok[j]+=1,cot[pok[j]]++;
53     }
54     //Otherwise
55     int res=stp;
56     memcpy(tp,cot,sizeof tp);
57     while (cot[4]>0&&cot[2]>1){
58         res++,cot[4]--,cot[2]-=2;
59     }
60     while (cot[4]>0&&cot[1]>1){
61         res++,cot[4]--,cot[1]-=2;
62     }
63     while (cot[3]>0&&cot[2]>0){
64         res++,cot[3]--,cot[2]--;
65     }
66     while (cot[3]>0&&cot[1]>0){
67         res++,cot[3]--,cot[1]--;
68     }
69     res+=cot[1]+cot[2]+cot[3]+cot[4];
70     ans=min(ans,res);
71     memcpy(cot,tp,sizeof tp);
72 }
73 void poker_situ2(){
74     int x,y; memset(p,0,sizeof p),memset(cnt,0,sizeof cnt),ans=n,big=0,sml=0;
75     for (int i=1; i<=n; i++){
76         scanf("%d%d",&x,&y);
77         if (x==0&&y==1) big++; else
78         if (x==0&&y==2) sml++; else{
79             if (x==2) p[13]++; else if (x==1) p[12]++; else p[x-2]++;
80         }
81     }
82     for (int i=1; i<=13; i++) cnt[p[i]]++; cnt[big]++,cnt[sml]++;
83     if (big+sml==2){
84         cnt[big]--,cnt[sml]--,big--,sml--;
85         DFS(1,n-2,p,cnt);
86         cnt[++big]++,cnt[++sml]++;
87     }
88     DFS(0,n,p,cnt);
89     printf("%d\n",ans);
90 }
91 int main(){
92     scanf("%d%d",&T,&n);
93     for ( ; T; T--) if (n<=4) poker_situ1(); else poker_situ2();
94     return 0;
95 }
View Code

 






以上是关于[NOIP 2016TG D1T3] 斗地主的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P2540 斗地主(NOIp2015提高组D1T3)

换教室 vijos2005 NOIP2016 D1T3 期望DP 图论最短路(雾)

洛谷 P1850 换教室(NOIp2016提高组D1T3)

NOIP2016tg滚粗记

[noip2011 d1t3] Mayan游戏

[luogu P3953] [noip2017 d1t3] 逛公园