斗地主大师
时间限制: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;
}