练练码力。
如果没有顺子,显然最小出牌次数可以贪心,优先出四带二,然后三带一或三带二,最后出对拍和单牌。
把大小王归到单排一类中,最后特判如果剩余的单排大于2,把这两张当成大小王一起出。
枚举所有出顺子的情况,用三个dfs,其中:
dfs(int now, int l, int tot, int times)
//now 当前到了第几小的牌
//l 当前顺子的长度
//tot 当前已经出了几次牌
//times 当前大小的顺子(三顺,二顺,单顺)重复搜索了几遍
关于为什么要用用times记录并重复搜索:
考虑这组牌
[egin{aligned}
3quad4quad5quad6quad6quad7quad7quad8quad9quad10
end{aligned}
]
显然答案为两次,分别是3到7,6到10,中间有重复的部分,所以需要重复搜索。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 30;
const int h[] = {14, 12, 13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
int n, ans = 1e9;
int card[N];
bool flag = false;
void check(int tt) {
int t[5]; memset(t, 0, sizeof(t));
for(int i = 1; i <= 15; i++) {
t[card[i]]++;
}
while(t[4]) {
if(t[1] >= 2) {
t[4]--; t[1] -= 2; tt++; continue;
} else if(t[2] >= 2) {
t[4]--; t[2] -= 2; tt++; continue;
} else if(t[2] >= 1) {
t[4]--; t[2]--; tt++; continue;
} else {
t[4]--; tt++; continue;
}
}
while(t[3]) {
if(t[1] >= 1) {
t[3]--; t[1]--; tt++; continue;
} else if(t[2] >= 1) {
t[3]--; t[2]--; tt++; continue;
} else {
t[3]--; tt++; continue;
}
}
while(t[2]) tt++, t[2]--;
if(flag && t[1] >= 2) {
t[1] -= 2; tt++;
}
tt += t[1];
ans = min(ans, tt);
return ;
}
void dfs2(int now, int l, int tot, int times) {
if(now == 13) {
if(l >= 5) {
if(times < 4) dfs2(1, 0, tot + 1, times + 1);
if(times == 4) check(tot + 1);
}
else if(l == 0) {
if(times < 4) dfs2(1, 0, tot, times + 1);
if(times == 4) check(tot);
}
return ;
}
if(card[now] >= 1) {
card[now] -= 1;
dfs2(now + 1, l + 1, tot, times);
card[now] += 1;
if(l >= 5) dfs2(now + 1, 0, tot + 1, times);
} else {
if(l >= 5) dfs2(now + 1, 0, tot + 1, times);
}
if(l == 0) dfs2(now + 1, 0, tot, times);
}
void dfs1(int now, int l, int tot, int times) {//2
if(now == 13) {
if(l >= 3) {
if(times < 4) dfs1(1, 0, tot + 1, times + 1);
if(times == 4) dfs2(1, 0, tot + 1, 0);
}
else if(l == 0) {
if(times < 4) dfs1(1, 0, tot, times + 1);
if(times == 4) dfs2(1, 0, tot, 0);
}
return ;
}
if(card[now] >= 2) {
card[now] -= 2;
dfs1(now + 1, l + 1, tot, times);
card[now] += 2;
if(l >= 3) dfs1(now + 1, 0, tot + 1, times);
} else {
if(l >= 3) dfs1(now + 1, 0, tot + 1, times);
}
if(l == 0) dfs1(now + 1, 0, tot, times);
}
void dfs(int now, int l, int tot, int times) {//3
if(now == 13) {
if(l >= 2) {
if(times < 4) dfs(1, 0, tot + 1, times + 1);
if(times == 4) dfs1(1, 0, tot + 1, 0);
}
else if(l == 0) {
if(times < 4) dfs(1, 0, tot, times + 1);
if(times == 4) dfs1(1, 0, tot, 0);
}
return ;
}
if(card[now] >= 3) {
card[now] -= 3;
dfs(now + 1, l + 1, tot, times);
card[now] += 3;
if(l >= 2) dfs(now + 1, 0, tot + 1, times);
} else {
if(l >= 2) dfs(now + 1, 0, tot + 1, times);
}
if(l == 0) dfs(now + 1, 0, tot, times);
}
int main() {
// freopen("data.in", "r", stdin);
int T; scanf("%d%d", &T, &n);
while(T--) {
memset(card, 0, sizeof(card));
ans = n; flag = false;
for(int i = 1, x, y; i <= n; i++) {
scanf("%d%d", &x, &y);
if(x == 0 && y == 1) card[14]++;
else if(x == 0 && y == 2) card[15]++;
else card[h[x]]++;
}
if(card[14] && card[15]) flag = true;
dfs(1, 0, 0, 0);
printf("%d
", ans);
}
return 0;
}