题目描述
众所周知,小 X 是一个身材极好、英俊潇洒、十分贪玩成绩却依然很好的奆老。
这不,他又找了他的几个好基友去他家里玩斗地主了……
身为奆老的小 X 一向认为身边人和自己一样的厉害,他坚信你和他一样有未卜先知的能力,他在他们玩完斗地主后,告诉了你他们的最终得分,希望你猜出他们最少玩了几局牌?
注意:小 X 他们至少玩了1局斗地主。
以下是斗地主的规则:发完牌后三人依次叫牌,可叫 1 分、2 分、3 分或不叫,所叫的分数称为底分,分数叫的高赢的多,输的也多。叫完后叫分最高者为地主,然后开始打牌,若地主获胜则地主得到 2 倍的底分,其余两家农民各输掉一份底分;若地主输了则地主输掉2倍的底分,其余两家农民各赢得一份底分。
输入
输入数据仅有一行包含四个用空格隔开的整数 n,a,b,c,分别表示小 X 他们玩了不超过n 局斗地主,最终三人的得分分别为 a,b,c
输出
输出一行一个整数表示最少打了几付牌,若这个得分在 n 付牌内不可能出现,则输出-1
样例输入
样例数据
5 0 0 0
样例输出
2
提示
开始时 3 人得分均为 0 分,第一副牌小 X 做了 3 分地主获胜,3 人得分变为 6,-3,-3,第二副牌小 X 继续做了 3 分地主失败,3 人得分归 0,符合输入要求,牌局结束。
对于 30%的数据,n<=5
对于另外 20%的数据,a,b,c 中有两个数相等
对于 100%的数据,n<=100,-300<=a,b,c<=300,a+b+c=0
题意
这个题当时想了好久整数分解,却发现直接爆搜即可,首先斗地主的规则是要知道的(有个哥们不知道规则,认为都叫相同的分,会随机选择一个地主,所以就自闭了一晚上),我们只到两个农民的状态是一样的,所以我们直接就看两个人的就行,两个人最后分数匹配了的话,第三个人也是匹配的。
思考一下,他的状态转移有几种,手写了18种:
- 都是农民:那就是要么赢了1,2,3,要么输了1,2,3。
- 一个农民一个地主,那么可能是地主赢了2,4,6,可能是地主输了2,4,6
一共 3 * 2 + 3 * 2 * 2 = 18
这个写一写,因该就能看出来,注意对应就行了,
const int p[20] = {0,1,2,3,-1,-2,-3,1,2,3,-1,-2,-3,-2,-4,-6,2,4,6};
const int q[20] = {0,1,2,3,-1,-2,-3,-2,-4,-6,2,4,6,1,2,3,-1,-2,-3};
接下来快乐的BFS就行了,这里为了防止走成环,你要做一个标记数组,又因为数据范围是[-300,300],比较难标记,所以就直接+400就行了。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<ctime>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1000;
const int p[20] = {0,1,2,3,-1,-2,-3,1,2,3,-1,-2,-3,-2,-4,-6,2,4,6};
const int q[20] = {0,1,2,3,-1,-2,-3,-2,-4,-6,2,4,6,1,2,3,-1,-2,-3};
struct In{
int x,y;
int st;
}nxt,now;
bool v[maxn][maxn];
int n,a,b,c;
void BFS()
{
memset(v,false,sizeof(v));
queue<In> qu;
a += 400;b += 400;
now.st = 0;
now.x = now.y = 400;
v[400][400] = true;
qu.push(now);
while(!qu.empty()){
if(now.st==n&&(now.x!=a||now.y!=b)){ //不能在规定步骤里得到,直接跳出就行了。
printf("-1\n");
return ;
}
now = qu.front();
qu.pop();
nxt.st = now.st + 1;
for(int i=1;i<=18;i++){
nxt.x = now.x + p[i];
nxt.y = now.y + q[i];
if(nxt.x==a&&nxt.y==b){
printf("%d\n",nxt.st);
return ;
}
if(!v[nxt.x][nxt.y]){
qu.push(nxt);
v[nxt.x][nxt.y] = true; //标记
}
}
}
return ;
}
int main(void)
{
scanf("%d%d%d%d",&n,&a,&b,&c);
if(a==0&&b==0&&c==0){
if(n>=2) printf("2\n");
else printf("-1\n");
}
else BFS();
return 0;
}
PS:当时做的时候,认为只要每次取出最小的st,就行了,所以就写了个优先队列,殊不知自己才开始是push的st=0的now,也不知道刚开始是怎么想的,可能菜是原罪吧。