有点恶心,特别是增强版
题解:大爆搜,搜索出顺子,贪心出散牌
据说加强版的标程都是贪心把除了顺子之外的散牌通过拆牌,贪心一次出完的。。而我太菜,只会出对子和单牌233
最后用几个奇奇怪怪的剪枝过了
#include<cstdio>
#include<algorithm>
#define re register
#define un unsigned
using namespace std;
const int MAXN = 20;
int T, n;
int Rest, Ans;
int Card[MAXN], Num[MAXN];
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
int k = 0; char ch = nc();
while(ch < '0' || ch > '9') ch = nc();
while(ch >= '0' && ch <= '9') k = (k<<3) + (k<<1) + ch - '0', ch = nc();
return k;
}
inline void Change(int u, int k){
Num[Card[u]]--; Card[u] += k; Num[Card[u]]++;
}
void dfs(int u){ //已走u步
// if(u >= Ans) return;
if(u + Num[3] + Num[4] >= Ans) return; //奇奇怪怪的剪枝,至今不明白
Ans = min(Ans, u + Num[1] + Num[2] + Num[3] + Num[4]);
//单顺子
if(Num[1] + Num[2] + Num[3] + Num[4] >= 5)
for(int len = Num[1] + Num[2] + Num[3] + Num[4]; len >= 5; len--){
for(int i = 2, j; i + len - 1 <= 13; i++){
for(j = i; j <= i + len - 1; j++) if(Card[j] < 1) break;
if(j > i + len - 1){
for(int j = i; j <= i + len - 1; j++) Change(j, -1);
dfs(u + 1);
for(int j = i; j <= i + len - 1; j++) Change(j, 1);
}
}
}
//双顺子
if(Num[2] + Num[3] + Num[4] >= 3)
for(int len = Num[2] + Num[3] + Num[4]; len >= 3; len--){
for(int i = 2, j; i + len - 1 <= 13; i++){
for(j = i; j <= i + len - 1; j++) if(Card[j] < 2) break;
if(j > i + len - 1){
for(int j = i; j <= i + len - 1; j++) Change(j, -2);
dfs(u + 1);
for(int j = i; j <= i + len - 1; j++) Change(j, 2);
}
}
}
//三顺子
if(Num[3] + Num[4] >= 2)
for(int len = Num[3] + Num[4]; len >= 2; len--){
for(int i = 2, j; i + len - 1 <= 13; i++){
for(j = i; j <= i + len - 1; j++) if(Card[j] < 3) break;
if(j > i + len - 1){
for(int j = i; j <= i + len - 1; j++) Change(j, -3);
dfs(u + 1);
for(int j = i; j <= i + len - 1; j++) Change(j, 3);
}
}
}
if(Num[4]) for(int i = 1; i <= 13; i++){
if(Card[i] == 4){
Change(i, -4);
//四带二对
if(Num[2] + Num[3] > 1 || Num[4])
for(int j = 1; j <= 13; j++){
if(Card[j] >= 2){
Change(j, -2);
for(int k = j; k <= 13; k++){
if(Card[k] >= 2){
Change(k, -2);
dfs(u + 1);
Change(k, 2);
}
}
Change(j, 2);
}
}
//四带一对
if(Num[2] || Num[3] || Num[4])
for(int j = 0; j <= 13; j++){
if(Card[j] >= 2){
Change(j, -2);
dfs(u + 1);
Change(j, 2);
}
}
//四带二
for(int j = 0; j <= 13; j++){
if(Card[j]){
Change(j, -1);
for(int k = j + 1; k <= 13; k++){
if(Card[k]){
Change(k, -1);
dfs(u + 1);
Change(k, 1);
}
}
Change(j, 1);
}
}
dfs(u + 1);
Change(i, 4);
}
}
if(Num[3]) for(int i = 1; i <= 13; i++){
if(Card[i] == 3){
Change(i, -3);
//三带二
if(Num[2] || Num[3] || Num[4])
for(int j = 1; j <= 13; j++){
if(j == i) continue;
if(Card[j] >= 2){
Change(j, -2);
dfs(u + 1);
Change(j, 2);
}
}
//三带一
for(int j = 0; j <= 13; j++){
if(j == i) continue;
if(Card[j] >= 1){
Change(j, -1);
dfs(u + 1);
Change(j, 1);
}
}
dfs(u + 1);
Change(i, 3);
}
}
return;
}
int main(){
T = read(), n = read();
while(T--){
Ans = n;
for(int i = 0; i <= 13; i++) Card[i] = 0;
for(int i = 0; i <= 4; i++) Num[i] = 0;
for(int i = 1; i <= n; i++){
int x = read(); read();
if(x == 0) Card[0]++;
else if(x == 1) Card[13]++;
else Card[x - 1]++;
}
for(int i = 0; i <= 13; i++){
Num[Card[i]]++;
}
dfs(0);
printf("%d\n", Ans);
}
return 0;
}