传送门
题意
给出一副扑克中的若干张牌,以及出扑克的规则。求最少出多少次牌将牌全部出完。
思路
搜索
牌的花色无任何影响。对于n张扑克,当顺子确定,其余的牌可通过贪心来确定出最小块数。搜索分别拿几个三顺,双顺,单顺,以及各个顺子的起止点。
注意不要弄错了各种扑克的大小:3< 4< 5< 6< 7< 8< 9< 10< J< Q< K< A< 2< 小王 < 大王
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int sm = 25;
const int Inf = 0x3f3f3f3f;
int ret;
int A,B,C,n;
int sum[sm],c[5];
int u,v;
int Min(int x,int y) { return x<y ? x : y; }
void Oth(int Ans) {
memset(c,0,sizeof(c));
for(int i = 0 ; i <= 13; ++i) c[sum[i]] ++;
while(c[4]&&c[2]>=2) c[4]--,c[2]-=2,++Ans;
while(c[4]&&c[1]>=2) c[4]--,c[1]-=2,++Ans;
while(c[4]&&c[2]) c[4]--,c[2]--,++Ans;
while(c[3]&&c[2]) c[3]--,c[2]--,++Ans;
while(c[3]&&c[1]) c[3]--,c[1]--,++Ans;
Ans += c[1]+c[2]+c[3]+c[4];
ret = Min(Ans,ret);
}
void Dfs(int Ans) {
if(Ans >= ret) return;
Oth(Ans);
int end;
for(int i = 2; i <= 13; ++i) {
end = i;
while(sum[end] >= 3) ++end;
if(end-i>=2) {
for(int j = i+1; j <= end-1; ++j) {
for(int k = i; k <= j; ++k)
sum[k] -= 3;
Dfs(Ans+1);
for(int k = i; k <= j; ++k)
sum[k] += 3;
}
}
}
for(int i = 2; i <= 13; ++i) {
end = i;
while(sum[end] >= 2) ++end;
if(end-i>=3) {
for(int j = i+2; j <= end-1; ++j) {
for(int k = i; k <= j; ++k)
sum[k] -= 2;
Dfs(Ans+1);
for(int k = i; k <= j; ++k)
sum[k] += 2;
}
}
}
for(int i = 2; i <= 13; ++i) {
end = i;
while(sum[end] >= 1) ++end;
if(end-i>=5) {
for(int j = i+4; j <= end-1; ++j) {
for(int k = i; k <= j; ++k)
sum[k] --;
Dfs(Ans+1);
for(int k = i; k <= j; ++k)
sum[k] ++;
}
}
}
}
int main() {
int T,get;
scanf("%d%d",&T,&n);
while(T--) {
ret = Inf;
memset(sum,0,sizeof(sum));
for(int i = 1; i <= n; ++i) {
scanf("%d%d",&u,&v);
if(u==1) u = 13; else if(u) u--;
sum[u] ++;
}
Dfs(0);
printf("%d\n",ret);
}
return 0;
}