NOIP2015 斗地主
题目描述
牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方
片的A 到K 加上大小王的共54 张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据
牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产
生影响。每一局游戏中,一副手牌由n 张牌组成。游戏者每次可以根据规定的牌型进行出
牌,首先打光自己的手牌一方取得游戏的胜利。现在,牛牛只想知道,对于自己的若干组
手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。需要注意的是,
本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。具体规则如下:
输入
第一行包含用空格隔开的2 个正整数T,N,表示手牌的组数以及每组手牌的张数。
接下来T 组数据,每组数据N 行,每行一个非负整数对Ai,Bi,表示一张牌,其中Ai
表示牌的数码,Bi 表示牌的花色,中间用空格隔开。特别的,我们用1 来表示数码A,11
表示数码J,12 表示数码Q,13 表示数码K;黑桃、红心、梅花、方片分别用1-4 来表示;
小王的表示方法为01,大王的表示方法为02。
输出
输共T 行,每行一个整数,表示打光第T 组手牌的最少次数。
solution
真是宇宙无敌大暴搜............(ps:反正我是对着测试点一个一个改过来的........)
不应该是状压:wxh和wq神犇都用状压,反正没改出来
牌型只有三种:1.顺子 2.带牌 3.单牌/对牌 (火箭也算对牌)
1.出牌的顺序不会影响答案
2.先搜顺子可以剪更多的枝,而且搜完顺子后,带牌和 单牌/对牌 可以用贪心求出
思路:
先 暴搜顺子 枚举 单/双/三顺子 左端点 右端点
之后用贪心求 其他牌型 (情况可能会很多.......)
我说说我遇到的坑点:
1.A可以当顺子
2.有不出顺子的出牌方式
3.4个2可以带2个王
4.注意贪心时 判断的优先级
5.4张牌 可以带两个相同的 单/对牌 例如:4个3 带4个2/带对2
这真是一个好题,不能浪费啊..
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<vector> 5 #define ll long long 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 using namespace std; 8 inline int minn(int a,int b){return a<b?a:b;} 9 10 int t,n; 11 int u,o,bushu; 12 int a[15]; 13 int limit[4]={0,5,3,2}; 14 15 void clear() 16 { 17 mem(a,0); 18 } 19 20 bool check(int l,int size) 21 { 22 if(l+limit[size]-1>13)return 0; 23 for(int i=l+limit[size]-1;i>=l;--i) 24 if(a[i]<size)return 0; 25 return 1; 26 } 27 28 void dfs(int now) 29 { 30 for(int size=1;size<=3;++size) 31 for(int l=2;l<=13;++l) 32 { 33 if(!a[l])continue; 34 if(!check(l,size))continue; 35 for(int r=l+limit[size]-1;r<=13;++r) 36 { 37 if(a[r]<size)break; 38 for(int k=l;k<=r;++k) 39 a[k]-=size; 40 dfs(now+1); 41 for(int k=l;k<=r;++k) 42 a[k]+=size; 43 } 44 } 45 46 int temp[15]; 47 memcpy(temp,a,sizeof(temp)); 48 49 int num1=0,num2=0,num3=0,num4=0; 50 for(int i=1;i<=13;++i) 51 { 52 if(temp[i]==1)++num1; 53 else if(temp[i]==2)++num2; 54 else if(temp[i]==3)++num3; 55 else if(temp[i]==4)++num4; 56 } 57 if(num4) 58 while(num4) 59 { 60 if(num1>=2){num1-=2;++now;--num4;continue;} 61 if(num1==1) 62 { 63 if(num2>=2){num2-=2;--num4;++now;continue;} 64 if(temp[14]){--num1;--temp[14];--num4;++now;continue;} 65 if(num2){--num2;--num4;++now;continue;} 66 } 67 if(num1==0) 68 { 69 if(num2>=2){num2-=2;--num4;++now;continue;} 70 if(temp[14]==2){temp[14]=0;--num4;++now;continue;} 71 if(temp[14]==1) 72 if(num2){--temp[14];--num2;++num1;--num4;++now;continue;} 73 } 74 break; 75 } 76 if(num3) 77 while(num3) 78 { 79 if(num1){--num1;--num3;++now;continue;} 80 if(temp[14]){--temp[14];--num3;++now;continue;} 81 if(num2){--num2;--num3;++now;continue;} 82 break; 83 } 84 85 if(temp[14]==2){temp[14]=0;++now;} 86 int qw=0; 87 if(num4>=2) 88 while(num4>=2){num4-=2;++qw;}//4带两个相同的对 89 90 bushu=minn(now+num1+num2+num3+num4+temp[14]+qw,bushu); 91 } 92 93 int main(){ 94 scanf("%d%d",&t,&n); 95 while(t--) 96 { 97 clear(); 98 for(int i=1;i<=n;++i) 99 { 100 scanf("%d%d",&u,&o); 101 if(!u)++a[14]; 102 else 103 if(u==1) 104 ++a[13]; 105 else 106 ++a[u-1]; 107 } 108 bushu=0x7fffffff; 109 dfs(0); 110 printf("%d\n",bushu); 111 } 112 //while(1); 113 return 0; 114 }