2018.11.01 bzoj4325: NOIP2015 鬥地主(貪心+搜尋)
阿新 • • 發佈:2018-11-06
傳送門
原來一直以為是一道大模擬。
沒想到是一道搜尋+最優性剪枝
如何搜最優呢?
我們考慮怎麼最快出完。
大概是應該儘量出當前能出出去最多的吧。
於是我們選擇優先出順子。
這樣做有什麼好處呢?
我們會發現除了順子以外的牌都能夠直接算最少需要出幾輪。
因此把順子出完之後更新答案就行了。
於是出牌優先順序:順子>四帶二>四帶一>三帶二>三帶一>對子>單牌
程式碼:
#include<bits/stdc++.h>
using namespace std;
int card[4]={0,5,3,2},r,n,a[15],ans,tot[5];
inline int calc(){
int ret=0;
memset(tot,0,sizeof(tot));
for(int i=0;i<=14;++i)if(i^1)++tot[a[i]];
while(tot[4]&&tot[2]>=2)++ret,--tot[4],tot[2]-=2;
while(tot[4]&&tot[1]>=2)++ret,--tot[4],tot[1]-=2;
while(tot[3]&&tot[2])++ret,--tot[3],--tot[2];
while(tot[3]&& tot[1])++ret,--tot[3],--tot[1];
return ret+tot[1]+tot[2]+tot[3]+tot[4];
}
inline void dfs(int dep){
if(dep>=ans)return;
for(int same=3,j,len;same;--same){
for(int i=3;i<=13;++i){
j=i;
while(a[j]>=same&&j<=14)++j;
--j;
if((len=j-i+1)<card[same])continue;
for (int k=i;k<=i+card[same]-2;++k)a[k]-=same;
for(int k=i+card[same]-1;k<=j;++k)a[k]-=same,dfs(dep+1);
for(int k=i;k<=j;++k)a[k]+=same;
}
}
ans=min(ans,dep+calc());
}
int main(){
scanf("%d%d",&r,&n),ans=n;
for(int i=1,x,y;i<=r;++i,memset(a,0,sizeof(a)),ans=n){
for(int j=1;j<=n;++j)scanf("%d%d",&x,&y),x=x==1?14:x,++a[x];
dfs(0),printf("%d\n",ans);
}
return 0;
}