【NOIP2015 DAY1 T3 】斗地主(landlords)

题目描述

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

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

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

具体规则如下:

输入输出格式

输入格式:

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

接下来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的规模如下:

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

 

 

 

【分析】

  我的记忆化搜索没加贪心在洛谷上85分,官方数组8个点。...

  用k进制记录状态,最多不超过200000。然后直接记忆化搜索了。

  听说->加一个贪心就可以A了。

 

  调了好久的说...

 

80分代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 #define Maxs 2000010
  8 
  9 int n,maxx;
 10 int sum[20],k[20],f[Maxs];
 11 
 12 int mymin(int x,int y) {return x<y?x:y;}
 13 
 14 void init()
 15 {
 16     int a,b;
 17     for(int i=0;i<=13;i++) sum[i]=0;
 18     for(int i=1;i<=n;i++)
 19     {
 20         scanf("%d%d",&a,&b);
 21         sum[a]++;
 22     }
 23     k[0]=1;
 24     for(int i=1;i<=13;i++) k[i]=k[i-1]*(sum[i-1]+1);
 25     maxx=k[13]*(sum[13]+1)-1;
 26     memset(f,63,sizeof(f));
 27     f[0]=0;
 28 }
 29 
 30 
 31 int ffind(int s)
 32 {
 33     if(f[s]<100) return f[s];
 34     int now[20];
 35     int ss=s;
 36     for(int i=13;i>=0;i--) if(sum[i])
 37     {
 38         if(i!=0) 
 39         {
 40             now[i]=ss/k[i];
 41             if(ss) ss%=k[i];
 42         }
 43         else now[i]=ss;
 44     }
 45     else now[i]=0;
 46     //-dan-shunzi
 47     for(int i=3;i<=9;i++)
 48     {
 49         bool ok=1;ss=s;
 50         for(int j=i;j<=i+4;j++)
 51         {
 52             if(now[j]==0) {ok=0;break;}
 53             ss-=k[j];
 54         }
 55         if(!ok) continue;
 56         f[s]=mymin(f[s],ffind(ss)+1);
 57         for(int j=i+5;j<=13;j++)
 58         {
 59             if(now[j]>=1)
 60             {
 61                 ss-=k[j];
 62                 f[s]=mymin(f[s],ffind(ss)+1);
 63             }
 64             else {ok=0;break;}
 65             
 66         }
 67         if(now[1]&&ok)
 68         {
 69             ss-=k[1];
 70             f[s]=mymin(f[s],ffind(ss)+1);
 71         }
 72     }
 73     if(now[1]&&now[13]&&now[12]&&now[11]&&now[10]) 
 74         f[s]=mymin(f[s],ffind(s-k[1]-k[13]-k[12]-k[11]-k[10])+1);
 75     //shuang shun
 76     for(int i=3;i<=11;i++)
 77     {
 78         bool ok=1;ss=s;
 79         for(int j=i;j<=i+2;j++)
 80         {
 81             if(now[j]<2) {ok=0;break;}
 82             ss-=k[j]*2;
 83         }
 84         if(!ok) continue;
 85         f[s]=mymin(f[s],ffind(ss)+1);
 86         for(int j=i+3;j<=13;j++)
 87         {
 88             if(now[j]>=2)
 89             {
 90                 ss-=2*k[j];
 91                 f[s]=mymin(f[s],ffind(ss)+1);
 92             } 
 93             else {ok=0;break;}
 94             
 95         }
 96         if(ok&&now[1]>=2)
 97         {
 98             ss-=2*k[1];
 99             f[s]=mymin(f[s],ffind(ss)+1);
100         }
101     }
102     if(now[1]>=2&&now[13]>=2&&now[12]>=2)
103           f[s]=mymin(f[s],ffind(s-2*k[1]-2*k[13]-2*k[12])+1);
104     //san shun
105     for(int i=3;i<=12;i++)
106     {
107         if(now[i]<3||now[i+1]<3) continue;
108         ss=s-k[i]*3-k[i+1]*3;
109         f[s]=mymin(f[s],ffind(ss)+1);
110         bool ok=1;
111         for(int j=i+2;j<=13;j++)
112         {
113             if(now[j]>=3)
114             {
115                 ss-=3*k[j];
116                 f[s]=mymin(f[s],ffind(ss)+1);
117             }
118             else {ok=0;break;}
119             
120         }
121         if(now[1]>=3&&ok)
122         {
123             ss-=3*k[1];
124             f[s]=mymin(f[s],ffind(ss)+1);
125         }
126     }
127     if(now[1]>=3&&now[13]>=3)
128           f[s]=mymin(f[s],ffind(s-3*k[1]-3*k[13])+1);
129     //4 dai 2
130     for(int i=1;i<=13;i++) if(now[i]==4)
131     {
132         ss=s-k[i]*4;
133         f[s]=mymin(f[s],ffind(ss)+1);
134         for(int j=0;j<=13;j++) if(i!=j&&now[j])
135         {
136             if(now[j]>=2) f[s]=mymin(f[s],ffind(ss-2*k[j])+1);
137             for(int l=j+1;l<=13;l++) if(l!=i&&now[l])
138             {
139                 if(now[j]>=2&&now[l]>=2&&j!=0)
140                   f[s]=mymin(f[s],ffind(ss-2*k[j]-2*k[l])+1);
141                 f[s]=mymin(f[s],ffind(ss-k[j]-k[l])+1);
142             }
143         }
144     }
145     //san dai x
146     for(int i=1;i<=13;i++) if(now[i]>=3)
147     {
148         ss=s-k[i]*3;
149         f[s]=mymin(f[s],ffind(ss)+1);
150         for(int j=0;j<=13;j++) if(now[j]>=1&&i!=j) f[s]=mymin(f[s],ffind(ss-k[j])+1);
151         for(int j=1;j<=13;j++) if(now[j]>=2&&i!=j) f[s]=mymin(f[s],ffind(ss-2*k[j])+1);
152     }
153     for(int i=0;i<=13;i++) if(now[i]>=1) f[s]=mymin(f[s],ffind(s-k[i])+1);
154     for(int i=0;i<=13;i++) if(now[i]>=2) f[s]=mymin(f[s],ffind(s-2*k[i])+1);
155     return f[s];
156 }
157 
158 int main()
159 {
160     int T;
161     scanf("%d%d",&T,&n);
162     while(T--)
163     {
164         init();
165         ffind(maxx);
166         printf("%d\n",f[maxx]);
167     }
168     return 0;
169 }
landlords

 

2016-08-06 10:57:25

 

posted @ 2016-08-06 10:54  konjak魔芋  阅读(480)  评论(0编辑  收藏  举报