思路:
大模拟,爆搜30分。
加一个贪心就能过。
单张和对子不用打,留到最后把散牌都打掉,无论怎么都会出现只剩单张和对子的情况,这种情况只能打散牌。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define R register using namespace std; const int N=50; int n,t,a[N],b[N],flag[N],ans,ton[N],tot; inline void dfs(R int cnt,R int use){ if(cnt>=ans)return; if(use==n){ ans=min(ans,cnt); return; } R int lst=0; for(R int i=3;i<=14;++i) { if(!ton[i])lst=0; else { ++lst; if(lst>=5) { for(R int k=i-lst+1;k<=i;++k) --ton[k]; dfs(cnt+1,use+lst); for(R int k=i-lst+1;k<=i;++k) ++ton[k]; } } } lst=0; for(R int i=3;i<=14;++i) { if(ton[i]<2)lst=0; else { ++lst; if(lst>=3) { for(R int k=i-lst+1;k<=i;++k)ton[k]-=2; dfs(cnt+1,use+lst*2); for(R int k=i-lst+1;k<=i;++k)ton[k]+=2; } } } lst=0; for(R int i=3;i<=14;i++) { if(ton[i]<3)lst=0; else { ++lst; if(lst>=2) { for(R int k=i-lst+1;k<=i;++k)ton[k]-=3; dfs(cnt+1,use+lst*3); for(R int k=i-lst+1;k<=i;++k)ton[k]+=3; } } } for(R int i=3;i<=15;++i) { if(ton[i]==4) { ton[i]-=4; for(R int j=3;j<=15;++j) { for(R int k=1;k<j;++k) { if(ton[j]>=2&&ton[k]>=2) { ton[j]-=2;ton[k]-=2; dfs(cnt+1,use+8);//四带二对 ton[j]+=2;ton[k]+=2; } if(ton[j]>=1&&ton[k]>=1) { --ton[j];--ton[k]; dfs(cnt+1,use+6);//四带二单 ++ton[j];++ton[k]; } } if(ton[j]>=2) { ton[j]-=2; dfs(cnt+1,use+6);//四带二 同 ton[j]+=2; } } ton[i]+=4; ton[i]-=4; dfs(cnt+1,use+4);//炸弹 ton[i]+=4; } if(ton[i]>=3) { ton[i]-=3; for(R int k=3;k<=15;++k) { if(ton[k]&&i!=k) { --ton[k]; dfs(cnt+1,use+4);//三带一 ++ton[k]; } if(ton[k]>=2) { ton[k]-=2; dfs(cnt+1,use+5);//三带二 ton[k]+=2; } } ton[i]+=3; ton[i]-=3; dfs(cnt+1,use+3);//三张 ton[i]+=3; } } for(R int i=3;i<=15;++i)if(ton[i]>=1)++cnt; ans=min(ans,cnt); } int main(){ scanf("%d%d",&t,&n); while(t--) { ans=0x3f3f3f3f; memset(ton,0,sizeof(ton)); for(R int i=1;i<=n;i++){ scanf("%d%d",&a[i],&b[i]); if(a[i]==1)a[i]=14; if(a[i]==2)a[i]=15; if(a[i]==0)a[i]=16; ton[a[i]]++; } if(ton[16]){//火箭 R int k=ton[16]; ton[16]=0; dfs(1,k); } else dfs(0,0); printf("%d ",ans); } return 0; }