BZOJ 4325: NOIP2015 斗地主

3 篇文章 0 订阅
3 篇文章 0 订阅

斗地主是偏题

我真是醉了这道题

还是没搞清楚能不能四带四。。(四可以拆成俩对对子。。)

还有四带二能不能带王炸。。。

题意不清啊。。

最后看标程发现可以带王炸不能带四。。

bi了哈士奇了为什么可以带王炸却不能带俩个一样的对子。。

因为纠结这些个东西去年跪在这里没去打所以只拿了20还是30?

其实是一道搜索。。讲明白还是不难的。。

记得把尖刀(A)标为14,因为它可以连在王(King)后面

每一种状态先看看不出连牌要几次

先把四带二出完,再出三带一,最后加上单牌和对,记录并更新ans

然后枚举连牌并继续向下搜索

实现起来也是不难的,也不长。。加上读入/输出优化才七十几行

#include<bits/stdc++.h>
#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;
}


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值