石油大 2019秋个人训练赛1 A 斗地主

题目描述
众所周知,小 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. 都是农民:那就是要么赢了1,2,3,要么输了1,2,3。
  2. 一个农民一个地主,那么可能是地主赢了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,也不知道刚开始是怎么想的,可能菜是原罪吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逃夭丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值