除过顺子的那些带牌和单打,可以直接算出来,得到一个答案的上界。
搜索时候只要找顺子,顺带剪几个枝就行了。
交上去rank1,吓傻。
/* Pigonometry */
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 18;
int n, a[maxn], cnt[5], ans;
inline int iread() {
int f = 1, x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return f * x;
}
inline int calc(int x[]) {
memset(cnt, 0, sizeof(cnt));
int res = 0;
for(int i = 0; i < maxn; i++) cnt[x[i]]++;
while(cnt[4] && cnt[2] >= 2) res++, cnt[4]--, cnt[2] -= 2;
while(cnt[4] && cnt[1] >= 2) res++, cnt[4]--, cnt[1] -= 2;
while(cnt[3] && cnt[2] >= 1) res++, cnt[3]--, cnt[2] -= 1;
while(cnt[3] && cnt[1] >= 1) res++, cnt[3]--, cnt[1] -= 1;
return res + cnt[1] + cnt[2] + cnt[3] + cnt[4];
}
inline void dfs(int x[], int step) {
if(step > ans) return;
ans = min(ans, step + calc(x));
for(int i = 2, j; i < maxn; i++) {
for(j = i; x[j] >= 3; j++);
if(j - i >= 2) {
for(int t = j; t - i >= 2; t--) {
for(int k = i; k < t; k++) x[k] -= 3;
dfs(x, step + 1);
for(int k = i; k < t; k++) x[k] += 3;
}
}
}
for(int i = 2, j; i < maxn; i++) {
for(j = i; x[j] >= 2; j++);
if(j - i >= 3) {
for(int t = j; t - i >= 3; t--) {
for(int k = i; k < t; k++) x[k] -= 2;
dfs(x, step + 1);
for(int k = i; k < t; k++) x[k] += 2;
}
}
}
for(int i = 2, j; i < maxn; i++) {
for(j = i; x[j] >= 1; j++);
if(j - i >= 5) {
for(int t = j; t - i >= 5; t--) {
for(int k = i; k < t; k++) x[k] -= 1;
dfs(x, step + 1);
for(int k = i; k < t; k++) x[k] += 1;
}
}
}
}
int main() {
int T = iread(), n = iread();
while(T--) {
memset(a, 0, sizeof(a));
for(int i = 1; i <= n; i++) {
int w = iread(), c = iread();
if(w == 1) w = 13;
else if(w) w--;
a[w]++;
}
ans = calc(a);
dfs(a, 0);
printf("%d\n", ans);
}
return 0;
}