为何顺子要暴力?c++
玩过斗地主的都知道,并非出越长的顺子越好,若是你有一组手牌,3,4,5,6,7,6,7,8,9,10
,你一下把最长的出了去,你会单两张牌,不如出两个顺子,因此顺子要暴力。spa
这是核心所在,也是不超时的缘由。code
能够先统计一下不一样牌个数的组数,而后再出牌,blog
那如何打出最优解?排序
首先必定要先出四带二,再出三带一,这是很容易想到的,由于四带能够带走两张。get
这样写正的行了吗?博客
固然不行,原题的随机数额能够过,加强版的必须考虑拆牌,并且还要考虑王炸的特殊状况,王算单牌,但能够当对出,明确这一点。it
何时该拆牌呢,对牌除了四带的状况不能拆,由于拆了可能多打一手牌。io
仔细想一想,三张和炸在单牌和对牌不少的时候是不能拆的,拆了就多大。class
当单牌和对牌数的和小于三张和炸的和,这就能够拆了
由于这时不拆的话没得带,只能单出,若是把三张拆成一单和一对,让其他的三张和炸带走,就会少一步。
四张的同理。
把一个炸拆成3张和单牌,再出一组四带二单和三带一
把一组三张拆成一对和一单,再出一组四带二单和三带二
三四张的比单牌和对牌多,拆着打
还多继续拆
四带两单
四带两对
对当作两单再四带
三张的太多了拆三张
把一组三张拆成单和对,再出三带一和三带二
三带一
三带二
还剩三张和炸,组合出
把两个三张拆成两个对和两个单,再出四带两对和四带两单
把一个炸拆成一对和两单,再出三带二和四带两单
把一个炸拆成两对,再出两组三带一对
同上,把一组三张拆成单和对,再出三带一和三带二
把一个炸拆成两对,再出一组四带两对
有双王一块出
出单牌
#include<bits/stdc++.h> using namespace std; int T,n; int pai[15]; int ans=0x3f3f3f3f; inline int read() { int tot=0,f=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-')f=-1; c=getchar(); } while(c>='0'&&c<='9') { tot=tot*10+c-'0'; c=getchar(); } return tot*f; } inline bool check() { for(int i=1;i<=14;i++) if(pai[i])return false; return true; } inline int sp() { bool flag=(pai[14]==2?1:0); int c[5],tot=0; memset(c,0,sizeof(c)); c[1]+=pai[14]; for(int i=1;i<=13;i++)c[pai[i]]++; /*for(int i=1;i<=4;i++) cout<<c[i]<<" "; cout<<endl;*/ while(c[3]==0&&c[1]==1&&c[2]==1&&c[4]>1)tot+=2,c[4]-=2,c[1]--,c[2]--; while(c[2]==0&&c[1]==1&&c[4]==1&&c[3]>1)tot+=2,c[3]-=2,c[1]--,c[4]--; if(c[3]+c[4]>c[1]+c[2])while(c[4]>0&&c[2]>0&&c[3]>0)tot++,c[2]--,c[3]--,c[1]++,c[4]--; if(c[3]+c[4]>c[1]+c[2])while(c[4]>0&&c[1]>0&&c[3]>0)tot++,c[1]--,c[3]--,c[2]++,c[4]--; while(c[4]>0&&c[1]>1)tot++,c[4]--,c[1]-=2; while(c[4]>0&&c[2]>1)tot++,c[4]--,c[2]-=2; while(c[4]>0&&c[2]>0)tot++,c[4]--,c[2]--; if(c[3]%3==0&&c[1]+c[2]<=1)while(c[3]>2)tot+=2,c[3]-=3; while(c[3]>0&&c[2]>0)tot++,c[3]--,c[2]--; while(c[3]>0&&c[1]>0)tot++,c[3]--,c[1]--; while(c[4]>1&&c[3]>1)tot+=2,c[3]-=2,c[4]-=2; while(c[4]>1&&c[3]>0)tot+=2,c[3]--,c[4]-=2; while(c[3]>1&&c[4]>0)tot+=2,c[4]--,c[3]-=2; while(c[4]>1)tot++,c[4]-=2; while(c[3]>2)tot+=2,c[3]-=3; /*for(int i=1;i<=4;i++) cout<<c[i]<<" "; cout<<endl;*/ if(c[1]>=2&&flag)return tot+c[2]+c[3]+c[4]+c[1]-1; else return tot+c[1]+c[2]+c[3]+c[4]; } inline void dfs(int cnt) { if(cnt>=ans)return; if(check()) { ans=min(ans,cnt); } int temp=sp(); /*for(int i=1;i<=14;i++) cout<<pai[i]<<" ";cout<<endl; */ ans=min(temp+cnt,ans); for(int i=1;i<=12;i++) { if(pai[i]<3)continue; for(int j=i+1;j<=12;j++) { if(pai[j]<3)break; if(j-i+1>=2) { for(int k=i;k<=j;k++)pai[k]-=3; dfs(cnt+1); for(int k=i;k<=j;k++)pai[k]+=3; } } } for(int i=1;i<=12;i++) { if(pai[i]<2)continue; for(int j=i+1;j<=12;j++) { if(pai[j]<2)break; if(j-i+1>=3) { for(int k=i;k<=j;k++)pai[k]-=2; dfs(cnt+1); for(int k=i;k<=j;k++)pai[k]+=2; } } } for(int i=1;i<=12;i++) { if(!pai[i])continue; for(int j=i+1;j<=12;j++) { if(!pai[j])break; if(j-i+1>=5) { for(int k=i;k<=j;k++)pai[k]--; dfs(cnt+1); for(int k=i;k<=j;k++)pai[k]++; } } } } int main() { //freopen("testdata.in","r",stdin); T=read();n=read(); while(T--) { memset(pai,0,sizeof(pai)); ans=0x3f3f3f3f; int ds,hs; for(int i=1;i<=n;i++) { ds=read();hs=read(); if(ds>=3&&ds<=13)pai[ds-2]++; else if(ds==0&&hs==1)pai[14]++; else if(ds==0&&hs==2)pai[14]++; else pai[ds+11]++; } dfs(0); cout<<ans<<endl; } return 0; }