Bootstrap

36. 跳格子游戏

题目

地上共有N个格子,你需要跳完地上所有的格子,但是格子间是有强依赖关系的,跳完前一个格子后,后续的格子才会被开启,格子间的依赖关系由多组steps数组给出,steps[0]表示前一个格子,steps[1]表示steps[0]可以开启的格子:

比如[0,1]表示从跳完第0个格子以后第1个格子就开启了,比如[2,1],[2,3]表示跳完第2个格子后第1个格子和第3个格子就被开启了

请你计算是否能由给出的steps数组跳完所有的格子,如果可以输出yes,否则输出no

说明:

1.你可以从一个格子跳到任意一个开启的格子

2.没有前置依赖条件的格子默认就是开启的

3.如果总数是N,则所有的格子编号为[0,1,2,3…N-1]连续的数组

输入描述:

输入一个整数N表示总共有多少个格子,接着输入多组二维数组steps表示所有格子之间的依赖关系

输出描述:

如果能按照steps给定的依赖顺序跳完所有的格子输出yes

否则输出no

示例1

输入

3

0 1

0 2

输出

yes

说明

总共有三个格子[0,1,2],跳完0个格子后第1个格子就开启了,跳到第0个格子后第2个格子也被开启了,按照0->1->2或者0->2->1的顺序都可以跳完所有的格子

示例2

输入

2

​1 0

0 1

输出

no

说明

总共有2个格子,第1个格子可以开启第0格子,但是第1个格子又需要第0个格子才能开启,相互依赖,因此无法完成

示例3

输入

6

0 1

0 2

0 3

0 4

0 5

输出

yes

说明

总共有6个格子,第0个格子可以开启第1,2,3,4,5个格子,所以跳完第0个格子之后其他格子都被开启了,之后按任何顺序可以跳完剩余的格子

示例4

输入

5

4 3

0 4

2 1

3 2

输出

yes

说明

跳完第0个格子可以开启格子4,跳完格子4可以开启格子3,跳完格子3可以开启格子2,跳完格子2可以开启格子1,按照0->4->3->2->1这样就跳完所有的格子

示例5

输入

4

1 2

1 0

输出

yes

说明

总共4个格子[0,1,2,3],格子1和格子3没有前置条件所以默认开启,格子1可以开启格子0和格子2,所以跳到格子1之后就可以开启所有的格子,因此可以跳完所有格子

一、问题分析

首先读题,仔细看描述中的内容,发现需求是

1.地上共有N个格子,

2.你需要跳完地上所有的格子,

3.但是格子间是有强依赖关系的,跳完前一个格子后,后续的格子才会被开启

4.格子间的依赖关系由多组step数组给出

5.steps[0]表示前一个格子

6.steps[1]表示step[0]可以开启的格子:比如[0,1]表示从跳完第0个格子以后第1个格子就开启了,

比如[2,1],[2,3]表示跳完第二个格子后第一个格子和第三个格子就开启了

7.请你计算是否能由给出的steps数组跳完所有的格子,如果可以输出yes,否则输出no

8.说明:(1)你可以从一个格子跳到任意一个开启的格子

(2)没有前置依赖条件的格子默认就是开启的

(3)如果总数是N,则所有的格子编号为[0,1,2,3...N-1]连续的数组

9.输入描述:输入一个整数N表示总共有多少个格子,接着输入多组二维数组steps表示所有格子之间的依赖关系

10.输出描述:如果能按照steps给定的依赖顺序跳完所有的格子输出yes否则输出no

二、解题思路

1.先考虑一下什么情况我们无法跳完所有的格子

因为默认所有的格子是开启的,所以只有在某几个格子形成依赖环且没有能破环的依赖关系的时候我们才无法跳完

比如[1,2][2,3][3,1]

我们必须跳到1才能跳到2,但是我们必须跳到3才能跳到1,而想要跳到3必须先跳到2

这样我们就无法跳完所有的格子

但是如果有类似于[0,1]这样的依赖关系就可以破解这个环,

就是说如果我们能找到一个不依赖于其他的数字就证明这个环可以解开

2.无法跳完所有格子的情况,肯定有数字即依赖于其他格子又是其他格子的前置格子

对于这些格子,如果我们能找到它的某个前置格子可以到达的话我们认为这样的格子可以到达

3.我们首先遍历所有的依赖关系,将是某些格子的前置格子标记为1

依赖于某些格子的格子标记为2

即依赖于某些格子也是某些格子的前置格子的标记为3

没有任何依赖关系的我们默认是0

4.遍历完所有依赖关系之后,对于被标记为1的那些格子因为它们是其他格子的前置格子

而且不依赖于其他的格子(因为没有被标记为3)我们可以将这些格子标记为0

并且将所有依赖于这些格子的格子也标记为0,然后将依赖于这些格子的格子也标记为0

5.如果我们这样标记之后还有没有被标记为0的格子那么证明我们无法到达所有格子。 

三、具体步骤

使用的语言是C

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

void helpFunc(int arr[][2], int idx, int i, int* nums) {
    for (int j = 0; j < idx; j++) {
        if (arr[j][0] == i) {
            nums[arr[j][1]] = 0;
            helpFunc(arr, idx, arr[j][1], nums);
        }
    }
}

int main() {
    int N;
    scanf("%d", &N);
    // printf("读取格子数目,一共有%d个格子\n", N);
    int arr[N][2];
    // 0代表前置格子,1代表依赖的格子,2代表是否访问过,3代表是否两个格子都能跳到
    int* nums = (int*)malloc(sizeof(int) * N);
    memset(nums, 0, sizeof(int) * N);
    int idx = 0;
    while (scanf("%d %d", &arr[idx][0], &arr[idx][1]) != EOF) {
        // printf("读取依赖关系,跳完%d才能跳%d\n", arr[idx][0], arr[idx][1]);
        if (nums[arr[idx][0]] == 0) {
            // 标识为1表示是某些格子的前置格子
            nums[arr[idx][0]] = 1;
            // printf("数字%d是其他数字的前置数字标记为1\n", arr[idx][0]);
        } else if (nums[arr[idx][0]]  == 2) {
            // printf("数字%d是依赖于其他数字,现在发现也是其他数字的前置数字标记为3\n", arr[idx][0]);
            nums[arr[idx][0]] = 3;
        }
        if (nums[arr[idx][1]] == 0) {
            // 标识为2表示依赖于某些格子
            nums[arr[idx][1]] = 2;
            // printf("数字%d依赖于其他数字标记为2\n", arr[idx][1]);
        } else if (nums[arr[idx][1]] == 1) {
            // printf("数字%d是其他数字的前置数字,现在发现也依赖于其他数字标记为3\n", arr[idx][0]);
            nums[arr[idx][1]] = 3;
        }
        idx++;
    }
    bool havesolution = true;
    // 首先将不依赖于其他数字的前置数字标记成0,同时将依赖于这些数字的数字标记为0
    for (int i = 0; i < N; i++) {
        if (nums[i] == 1) {
            nums[i] = 0;
            helpFunc(arr, idx, i, nums);
        }
    }
    for (int i = 0; i < N; i++) {
        // printf("现在的每个数字的标记是%d %d\n", i, nums[i]);
        if(nums[i] != 0) {
            havesolution = false;
        }
    }
    if (havesolution == true) printf("yes\n");
    else printf("no\n");
    free(nums);
}

;