斗地主大师题解(宽搜)

文章讨论了一个关于斗地主大师利用其特殊能力在斗地主游戏中调整欢乐豆数量的问题,目的是从初始欢乐豆P变为幸运数字Q,通过最少的局数计算策略。
摘要由CSDN通过智能技术生成

斗地主大师

时间限制:1000ms 内存限制:65536kB

描述

斗地主大师今天有P个欢乐豆,他夜观天象,算出了一个幸运数字Q,如果他能有恰好Q个欢乐豆,就可以轻松完成程设大作业了。

斗地主大师显然是斗地主大师,可以在斗地主的时候轻松操控游戏的输赢。
1.他可以轻松赢一把,让自己的欢乐豆变成原来的Y倍
2.他也可以故意输一把,损失X个欢乐豆(注意欢乐豆显然不能变成负数,所以如果手里没有X个豆就不能用这个能力)
而斗地主大师还有一种怪癖,扑克除去大小王只有52张,所以他一天之内最多只会打52把斗地主。
斗地主大师希望你能告诉他,为了把P个欢乐豆变成Q个,他至少要打多少把斗地主?

输入

第一行4个正整数 P,Q,X,Y 0< P,X,Q <= 2^31, 1< Y <= 225

输出

输出一个数表示斗地主大师至少要用多少次能力 如果打了52次斗地主也不能把P个欢乐豆变成Q个,请输出一行 “Failed”

样例输入

样例输入1

2 2333 666 8

样例输入2

1264574 285855522 26746122 3

样例输出

输出样例1:

Failed

输出样例2:

33

题解

首先按要求输入p,q,x,y。注意它们上限为2^31,必须用long long定义

long long p,q,x,y;
cin>>p>>q>>x>>y;

其次以p(欢乐豆的数量)为参数宽搜

bfs(p);
void bfs(int a)//为避免重名,参数名定义为a
{
}

宽搜的队列需要记录两个值:现有欢乐豆数、当前局数。且欢乐豆数上限超出int上限,要用long long定义

struct node
{
	long long n,d;//n:当前欢乐豆数 d:当前局数
};
queue<node> qu;

我们还需要一个标记数组,避免重复搜索

map<long long,int> m;

接下来我们回到函数,将初值加入队列并标记

qu.push({a,0});
m[a]=1;

这里有一种要考虑的特殊情况:现有的欢乐豆数p正好等于幸运数q。这种情况直接输出0

if(a==q)//之前用a记录的p
{
	cout<<0;
	return;
}

然后进入循环,并且定义b和h,来记录预先计算出的可能欢乐豆数和队头

while(qu.size())
{				
	long long b;
	node h=qu.front();
	qu.pop();
}

这里可以剪枝,如果欢乐豆数减去52次(局数上限)x(每次可以减去的数量),还是比q(幸运数)大,那么乘也无济于事,因为乘只增不减。这样就可以判断当前情况无解,跳至下一层

if(h.n>q&&h.n-52*x>q)
{
	continue;
}

如果某次欢乐豆变成了q个,那么输出这次局数

if(h.n==q)
{
	cout<<qu.front().d;
	return;
}

如果局数超过52(最大限),那么输出failed并结束

if(h.d>52)
{
	cout<<"failed";
	return;
}

处理完当前层,我们接着处理下一层
首先看乘y的情况,如果乘y后的数量没有超限,并且也没有与之前重复,那么让它入队并做上标记

b=h.n*y;//预先算出乘y后的数
if(b>=0&&b<=pow(2,31)&&m[b]==0)//判断是否越超限或重复
{
	qu.push({b,h.d+1});//入队
	m[b]==1;//标记
}

减x的情况也是一样

b=h.n-x;//预先算出减x后的数
if(b>=0&&b<=pow(2,31)&&m[b]==0)//判断是否超限或重复
{
	qu.push({b,h.d+1});//入队
	m[b]==1;//标记
}

完整代码

#include<bits/stdc++.h>
using namespace std;
long long p,q,x,y;
map<long long,int> m;//标记数组 
struct node
{
	long long n,d;//n:当前欢乐豆数 d:当前局数 
};
queue<node> qu;//队列 
void bfs(int a)//为避免重名,用a来表示p 
{
	qu.push({a,0});//入队 
	m[a]=1;//标记 
	if(a==q)//如果欢乐豆的初值和幸运数相等,输出0 
	{
		cout<<0;
		return;
	}
	while(qu.size())
	{				
		long long b;//b:用于储存预先算出的可能欢乐豆数 
		node h=qu.front();//h:保存队头 
		qu.pop();//弹出队头 
		if(h.n>q&&h.n-52*x>q)//剪枝 
		{
			continue;
		} 
		if(h.n==q)//如果成功,输出当前局数 
		{
			cout<<qu.front().d;
			return;
		}
		if(h.d>52)//如果局数超限,输出failed 
		{
			cout<<"failed";
			return;
		}
		b=h.n*y;//记录当前欢乐豆数乘y后的值 
		if(b>=0&&b<=pow(2,31)&&m[b]==0)//判断是否超限或重复 
		{
			qu.push({b,h.d+1});//入队 
			m[b]==1;//标记 
		}
		b=h.n-x;//记录当前欢乐豆数减x后的值 
		if(b>=0&&b<=pow(2,31)&&m[b]==0)//判断是否超限或重复 
		{
			qu.push({b,h.d+1});//入队 
			m[b]==1;//标记 
		}
	}
}
int main()
{
	cin>>p>>q>>x>>y;//输入欢乐豆数、幸运数、可以减多少、可以乘多少 
	bfs(p);//以欢乐豆数为参数,宽搜 
	return 0;
}
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值