2022-04-19每日刷题打卡

2022-04-19每日刷题打卡

代码源——每日一题

走不出的迷宫 - 题目 - Daimayuan Online Judge

有一个 H 行 W 列的迷宫(行号从上到下是 1−H,列号从左到右是 1−W),现在有一个由 . 和 # 组成的 H 行 W 列的矩阵表示这个迷宫的构造,. 代表可以通过的空地,# 代表不能通过的墙。

现在有个人从 起点 (1,1) 开始走,他每一步只能往右走一格或者往下走一格,并且他不能跨越迷宫的边界。他会一直走,直到没有可以走的路时停下来。

请问这个人最多可以经过多少个格子?

输入格式
第一行两个整数 H,W,表示迷宫有 H 行 W 列。

接下来一个 H 行 W 列的由 . 和 # 组成的矩阵,表示迷宫的构造。

注意:保证 (1,1) 的位置一定是 .。

输出格式
一个整数,表示最多步数。

输出格式

一个整数,表示最多步数。

样例输入1

3 4
.#..
..#.
..##

样例输出1

4

样例输入2

1 1
.

样例输出2

1

样例输入3

5 5
.....
.....
.....
.....
.....

样例输出3

9

数据规模

对于全部数据保证 1≤H,W≤100

我采用的是dp做法,当然bfs也是可以的,但是要注意给每个位置打上标记防止走重复了。

dp数组dp[i] [j]的意思是:当走到i行j列的位置上是,走过的最长路径长度。因为我们每次只能往左走或者往下走,这说明了我们想走到 [i] [j]只能从[i-1] [j]往下走一步得到或者从[i] [j-1]往右走一步得到,所以状态转移方程为:dp[i] [j]=max(dp[i-1] [j],dp[i] [j-1])+1。

但是直接这样写是会有问题的,我们要注意判断一下两个特殊性,

一是当前位置是“#”,此时这位置是无法走到的,所以dp[i] [j]就是0

二是虽然当前是“.”,但却无法走到当前位置的情况,比如这么一个样例:

3 10
..#.......
##........
..........

答案应当是2,但要是我们不判断情况2,答案是会错误的,我们实际能走的地方只有左上角的地方,但是我们之前的计算方法会去计算后面的那些点,但实际上那些点是走不到的。所以我们应该判断一下,如果上方和前方是0(即这两处位置也走不到)那你本身也该是0。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;

char c[110][110];
PII que[10000];
int moves[110][110];

int main()
{
    cin.sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, m, res = 1;
    string s;
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        cin >> s;
        for (int j = 0; j < m; j++)
            c[i][j] = s[j];
    }

    moves[0][0] = 1;
    for (int i = 1; i < n; i++)
        if (c[i][0] == '.')
        {
            moves[i][0] = moves[i - 1][0] + 1;
            res = max(moves[i][0], res);
        }
        else break;

    for (int i = 1; i < m; i++)
        if (c[0][i] == '.')
        {
            moves[0][i] = moves[0][i - 1] + 1;
            res = max(res, moves[0][i]);
        }
        else break;
    for (int i = 1; i < n; i++)
        for (int j = 1; j < m; j++)
            if (c[i][j] == '.')
            {
                if (moves[i - 1][j] == 0 && moves[i][j - 1] == 0)continue;
                moves[i][j] = max(moves[i - 1][j], moves[i][j - 1]) + 1;
                res = max(res, moves[i][j]);
            }
    cout << res;

    return 0;
}
石子游戏 II - 题目 - Daimayuan Online Judge

Alice 和 Bob 正在玩一个关于石头的游戏。

共有 n 堆石头,其中第 i 堆最初含有 ai 个石子。

他们轮流执行下列操作之一,从 Alice 开始。

把一堆奇数的石头劈成两堆,两堆都不能空。

把两堆偶数的石头合成一堆。

不能执行任何操作的人将输掉游戏。

假设 Alice 和 Bob 都足够聪明,你知道谁会赢得游戏吗?

输入格式

第一行包含一个整数 n (1≤n≤106)

第二行包含 n 个正整数 a1,…,an (1≤a1,…,an≤109)

输出格式

Alice 或 Bob,表示最终赢家

样例输入

2
2 2

样例输出

Alice

博弈论。

让我们来分情况讨论一下怎么样才能赢:

一、只剩下一堆石头,且这堆石头是偶数。

二、剩下的石头都是数量为1。

三、只有一个是偶数堆石头,其它都是数量为1。

那么也就是说,我们想赢,就是把所有的偶数都合起来,奇数都切成1。然后我们来看一下步骤:

如果有n个数量为偶数的石头,那我们将会进行n-1次操作才能把所有石头合成一堆。

如果是奇数的石头,我们可以先切一刀后把它变成一个1和一个偶数石头(不一定要对半分的啊),如果还有偶数石头,就可以把这个偶数石头和另一堆合起来。那么看起来我们要记录一下大于1的奇数石头和大于0的偶数石头的个数?

其实不用这么麻烦,你想:

如果只有一个奇数石头,那我们alice批完一刀后就变成一个1和一个偶数石头,bob就不能行动了。

如果只有两个奇数石头,那我们alic和bob各批完一刀后,变成了两个1石头和两个偶数石头,此时alice把这两个偶数石头合起来,bob又没事干了。

所以其实不管奇数石头的数量,最后都该是alice赢(除非奇数石头全是1,那么Alice就直接输了)。

所以我们就看偶数的情况就可以了,而偶数情况也很直观,那就是要进行(偶数石头数量-1)次操作,这样我们就很容易的计算出哪个角色是完成最后一次合成操作的人。

此时我们就可以得到结论了:

大于0的偶数石头数量为0时,只要奇数石头有大于1的,那就是alic赢

大于0的偶数石头数量不为0时,数量为偶数时Alice赢,反之bob赢

其它情况都是bob赢

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;

inline int read() {
    int x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x;
}

int main()
{
    cin.sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n = read();
    int x, res = 0;
    bool flag = false;
    for (int i = 0; i < n; i++)
    {
        x = read();
        if (x % 2 == 0)res++;
        if (x != 1)flag = true;
    }
    if ((res != 0 && res % 2 == 0) || (res == 0 && flag))
    {
        cout << "Alice" << endl;
    }
    else cout << "Bob" << endl;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值