题目
题解
#include
using namespace std;
#define X f[i][j][k][l]
inline void M(int &x,int y){
if (x>y) x=y;
}
int p[15],f[25][25][25][25],x,y,K,h[5],T,n,i,ans,shun[4]={0,5,3,2},j,k,l;
int calc(int O,int t,int T,int F,int K){
//O表示one,t表示two,T表示three,F表示four,K表示king,王的个数
if (K==1) K=0,O++;
if (!K) return f[F][T][t][O];
return min(f[F][T][t][O]+1,f[F][T][t][O+2]);
}
void dfs(int now){
if (now>ans) return;
memset(h,0,sizeof(h));
for (int i=2;i<=14;i++) h[p[i]]++;
M(ans,now+calc(h[1],h[2],h[3],h[4],K));
for (int k=1;k<=3;k++)
for (int i=3,j;i<=14;i++){
for (j=i;j<=14 && p[j]>=k;j++){
p[j]-=k;
if (j-i+1>=shun[k]) dfs(now+1);
}
for (j--;j>=i;j--) p[j]+=k;
}
}
int main(){
scanf("%d%d",&T,&n);
for (i=0;i<=n/4;i++)
for (j=0;j<=n/3;j++)
for (k=0;k<=n/2;k++)
for (l=0;i*4+j*3+k*2+l<=n;l++){
//i个4,j个3,k个2,l个1
X=i+j+k+l;
if (i){
M(X,f[i-1][j+1][k][l+1]);//四拆成三和一个单
if (k>1) M(X,f[i-1][j][k-2][l]+1);//四带两对
if (i>1) M(X,f[i-2][j][k][l]+1);//两炸拆成四带两对
if (k) M(X,f[i-1][j][k-1][l]+1);//四带两张成对的单
if (l>1) M(X,f[i-1][j][k][l-2]+1);//四带二
M(X,f[i-1][j][k][l]+1);//直接炸
}
if (j){
M(X,f[i][j-1][k+1][l+1]);//三拆成一对一单
if (k) M(X,f[i][j-1][k-1][l]+1);//三带一对
if (l) M(X,f[i][j-1][k][l-1]+1);//三带一
M(X,f[i][j-1][k][l]+1);//直接三个
}
if (k) M(X,f[i][j][k-1][l]+1);//直接出对子
if (l) M(X,f[i][j][k][l-1]+1);//直接出单
}
while (T--){
memset(p,0,sizeof(p));K=0;
for (i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if (!x) K++;
else if (x==1) p[14]++;
else p[x]++;
}
ans=n;
dfs(0);
printf("%d\n",ans);
}
}