P2668 鬥地主 (NOIP 提高 2015)
阿新 • • 發佈:2020-09-10
P2668
首先,如上圖,我們有 三帶一,三帶二,單順子,雙順子,三順子和四帶二 這幾種特殊的牌型,在上圖的牌型中,火箭也是比較特殊的,但是本題中只是需要兩張鬼王牌即可,所以我們可以把火箭看為對子牌這種普通牌型
所以,我們只要在搜尋的時候對於上面的幾種特殊牌型進行特別的處理,最後剩下的手牌中每種相同點數的牌一定可以以單張牌,對子牌,三張牌和炸彈牌幾種牌型打出
除此之外,還要注意每種牌型對於牌的特殊限制(如順子中不能有 "2" 和鬼王),相應的對列舉的牌進行調整
原始碼:
#include<iostream> #include<cstdio> #include<cstring> #include<math.h> #include<algorithm> #define ll long long using namespace std; const ll maxn=50; ll T,n,ans,num,c; ll vis[maxn]; inline void dfs(ll x) { if(x>=ans) return ;//最優性剪枝 ll len=0; for(int i=3;i<=14;i++)//單順子 { if(vis[i]==0) len=0; else { len++; if(len>=5) { for(int j=i;j>=i-len+1;j--) vis[j]--; dfs(x+1); for(int j=i;j>=i-len+1;j--) vis[j]++; } } } len=0; for(int i=3;i<=14;i++)//雙順子 { if(vis[i]<=1) len=0; else { len++; if(len>=3) { for(int j=i;j>=i-len+1;j--) vis[j]-=2; dfs(x+1); for(int j=i;j>=i-len+1;j--) vis[j]+=2; } } } len=0; for(int i=3;i<=14;i++)//三順子 { if(vis[i]<=2) len=0; else { len++; if(len>=2) { for(int j=i;j>=i-len+1;j--) vis[j]-=3; dfs(x+1); for(int j=i;j>=i-len+1;j--) vis[j]+=3; } } } for(int i=2;i<=14;i++) { if(vis[i]==3) { vis[i]-=3; for(int j=2;j<=15;j++)//三帶一 { if(vis[j]>=1&&j!=i) { vis[j]--; dfs(x+1); vis[j]++; } } for(int j=2;j<=14;j++)//三帶二 { if(vis[j]>=2&&j!=i) { vis[j]-=2; dfs(x+1); vis[j]+=2; } } vis[i]+=3; } else if(vis[i]==4)//有四張牌可以分為出三張留一張和全部都出 { vis[i]-=3; for(int j=2;j<=15;j++)//三帶一 { if(vis[j]>=1&&j!=i) { vis[j]-=1; dfs(x+1); vis[j]+=1; } } for(int j=2;j<=14;j++)//三帶二 { if(vis[j]>=2&&j!=i) { vis[j]-=2; dfs(x+1); vis[j]+=2; } } vis[i]+=3; vis[i]-=4; for(int j=2;j<=15;j++) { if(vis[j]>=1&&j!=i)//四帶兩張 { vis[j]--; for(int k=2;k<=15;k++) { if(vis[k]>=1&&j!=k) { vis[k]--; dfs(x+1); vis[k]++; } } vis[j]++; } } for(int j=2;j<=14;j++)//四帶兩對 { if(vis[j]>=2&&j!=i) { vis[j]-=2; for(int k=2;k<=14;k++) { if(vis[k]>=2&&k!=j) { vis[k]-=2; dfs(x+1); vis[k]+=2; } } vis[j]+=2; } } vis[i]+=4; } } for(int i=2;i<=15;i++)//全部出完 { if(vis[i]) x++; } ans=min(ans,x); } int main(void) { // freopen("P2668_3.in","r",stdin); // freopen("z.out","w",stdout); scanf("%lld%lld",&T,&n); while(T--) { memset(vis,0,sizeof(vis)); ans=9999999999; for(int i=1;i<=n;i++)//把牌按照大小以 3 為基準排好 { scanf("%lld%lld",&num,&c); if(num==1) num=14; if(num==0) num=15; vis[num]++; } dfs(0); // if(ans==2) ans=3; printf("%lld\n",ans); } return 0; }