bzoj|BZOJ 4325: NOIP2015 斗地主

斗地主是偏题
我真是醉了这道题
还是没搞清楚能不能四带四。。(四可以拆成俩对对子。。)
还有四带二能不能带王炸。。。
题意不清啊。。
最后看标程发现可以带王炸不能带四。。
bi了哈士奇了为什么可以带王炸却不能带俩个一样的对子。。
因为纠结这些个东西去年跪在这里没去打所以只拿了20还是30?
其实是一道搜索。。讲明白还是不难的。。
记得把尖刀(A)标为14,因为它可以连在王(King)后面
每一种状态先看看不出连牌要几次
先把四带二出完,再出三带一,最后加上单牌和对,记录并更新ans
然后枚举连牌并继续向下搜索
实现起来也是不难的,也不长。。加上读入/输出优化才七十几行

#include #define g getchar() #define ll long long #define inf 0x3f3f3f3f using namespace std; inline ll read(){ ll x=0,f=1; char ch=g; for(; ch<'0'||ch>'9'; ch=g)if(ch=='-')f=-1; for(; ch>='0'&&ch<='9'; ch=g)x=x*10+ch-'0'; return x*f; } inline void out(ll x){ int a[25],wei=0; if(x<0)putchar('-'),x=-x; for(; x; x/=10)a[++wei]=x%10; if(wei==0){puts("0"); return; } for(int j=wei; j>=1; --j)putchar('0'+a[j]); putchar('\n'); } int ans,T,n; int cnt[5],hand[16]; void dfs(int x){ if(x>ans)return; int rest=0; memset(cnt,0,sizeof(cnt)); for(int i=0; i<15; ++i)cnt[hand[i]]++; for(; cnt[4]; ){ cnt[4]--,rest++; //炸弹 if(cnt[2]>=2)cnt[2]-=2; //能不能带二 else if(cnt[1]>=2)cnt[1]-=2; } for(; cnt[3]; ){ cnt[3]--,rest++; //三张牌 if(cnt[2])cnt[2]--; //能不能带一 else if(cnt[1])cnt[1]--; }//我在思考把三带一和四带二写成子程序是不是更简洁? if(hand[0]&&hand[1]&&cnt[1]>=2)--rest; //看看剩下的单牌有没有王炸 rest+=cnt[1]+cnt[2]; ans=min(rest+x,ans); for(int i=3,j; i<15; ++i){//单顺子 for(j=i; hand[j]&&j<15; ++j){ hand[j]--; if(j-i+1>=5)dfs(x+1); //如果多于5张向下搜索 } for(; j>i; )hand[--j]++; } for(int i=3,j; i<=15; ++i){//双顺子 for(j=i; hand[j]>=2&&j<15; ++j){ hand[j]-=2; if(j-i+1>=3)dfs(x+1); } for(; j>i; )hand[--j]+=2; } for(int i=3,j; i<=15; ++i){//三顺子 for(j=i; hand[j]>=3&&j<15; ++j){ hand[j]-=3; if(j-i+1>=2)dfs(x+1); } for(; j>i; )hand[--j]+=3; }//我在思考是不是把顺子什么写个子程序会更简洁? } int main(){ T=read(); n=read(); for(; T--; ){ ans=n; memset(hand,0,sizeof(hand)); for(int i=1; i<=n; ++i){ int x=read(),y=read(); if(x==0)hand[y-1]++; //Joker要分开存,因为它们并不能组成对牌 else if(x==1)hand[14]++; else hand[x]++; } dfs(0); out(ans); } return 0; }



【bzoj|BZOJ 4325: NOIP2015 斗地主】发现一个人程序写错然而AC了让我很难过,而且UO(钩)的斗地主因为数据是随机的所以不能Hack。。

    推荐阅读