0
点赞
收藏
分享

微信扫一扫

1726 挤奶顺序(分类讨论、模拟)

念川LNSC 2022-02-26 阅读 51
算法

1. 问题描述:

Farmer John 有 N 头奶牛,编号为 1…N。他每天都要给他的奶牛们挤奶。奶牛的社会结构非常复杂,其结构有两个关键特性。首先,有 M 头奶牛的地位等级分明,按照地位越高越早挤奶的规则,这些奶牛的相对挤奶顺序是固定的。此外,有 K 头奶牛的具体挤奶顺序也是固定的,比如,奶牛 4 必须在所有奶牛中的第二位挤奶。幸运的是,Farmer John 总是能够以一种满足所有这些情况的顺序给他的奶牛们挤奶。不幸的是,奶牛 1 最近生病了,所以 Farmer John 想要尽早给这头奶牛挤奶,使得她可以回到牛棚休息。请帮助 Farmer John 求出奶牛 1 可以在挤奶顺序中出现的最早位置。

输入格式

第一行包含 N,M,K,表示 Farmer John 有 N 头奶牛,其中 M 头形成了社会阶层,K 头需要在挤奶顺序中处于一个特定的位置。下一行包含 M 个不同的整数 mi。在这一行出现的奶牛必须以与她们在这行出现的顺序相同的顺序进行挤奶。下面 K 行,每行包含两个整数 ci 和 pi,表示奶牛 ci 一定要在第 pi 位进行挤奶。输入数据保证:在这些限制之下,Farmer John 能够建立一个符合要求的挤奶顺序。

输出格式

输出奶牛 1 可以在挤奶顺序中出现的最早位置。

数据范围

2 ≤ N ≤ 100,
1 ≤ M,K < N,
1 ≤ mi,ci,pi ≤ N

输入样例:

6 3 2
4 5 6
5 3
3 1

输出样例:

4
样例解释
在这个例子中,Farmer John 有六头奶牛,其中奶牛 1 生病了。他的挤奶顺序应该为奶牛 4 在奶牛 5 之前,奶牛 5 在奶牛 6 之前。此外,Farmer John 必须要第一个给奶牛 3 挤奶,第三个给奶牛 5 挤奶。FJ必须第一个给奶牛 3 挤奶,由于奶牛 4 必须要在奶牛 5 之前,奶牛 4 一定是第二个挤奶的,然后奶牛 5 第三个。于是,奶牛 1 最早在挤奶顺序中出现的位置是第四个。
来源:https://www.acwing.com/problem/content/description/1728/

2. 思路分析:

分析题目可以知道已知k头牛的位置是固定的,m头牛的相对顺序也是固定的,我们需要求解在满足题目限制的前提下使得编号为1的牛放置的位置越靠前,可以发现其实对应三种情况,分类讨论即可:① 编号为1的牛已经有固定位置了;② 编号为1的牛需要满足在m头牛的相对顺序中;③ 不在①②中的限制中;对于①的情况其实很容易判断,我们在输入数据的时候判断是否存在1即可,主要是②③情况的判断,对于情况②因为编号为1的牛在m头牛的相对顺序限制中所以要想使得位置越靠前那么需要在剩余的位置中从前往后放置m头牛;对于情况③要想使得编号为1的牛的位置越靠前那么需要使得在剩余的位置中从后往前放置m头牛那么从前往后第一个没有放置的位置就是编号为1的牛的位置;需要特别注意的是对于情况②③,如果当前遍历的牛已经有固定位置了那么就不用放置当前的牛了,可以发现分析起来还是比较容易但是代码比较难写。

3. 代码如下:

class Solution:
    def process(self):
        n, m, k = map(int, input().split())
        # p[i]表示编号为i的牛放置的位置, q存储牛需要满足的相对顺序, st表示当前的位置是否已经被牛占用了
        p, st = [-1] * (n + 10), [0] * (n + 10)
        q = list(map(int, input().split()))
        # 
        for i in range(k):
            a, b = map(int, input().split())
            p[a] = b
            # 表示位置b已经被占了
            st[b] = 1
            # 说明编号为1的牛位置是确定的
            if a == 1: return b
        flag = 0
        for i in range(m):
            # 说明编号为1的牛在m中
            if q[i] == 1: 
                flag = 1
                break
        if flag == 1:
            # 编号为1的牛仔m中说明我们需要从前往后放置这些牛
            # j表示尝试将当前枚举的牛放到当前的位置j
            j = 1
            for i in range(m):
                # 跳过被占用的位置
                while st[j] == 1: j += 1
                # 当前需要放置的牛已经有固定位置了那么就不用放置当前的牛更新j即可
                if p[q[i]] != -1:
                    j = p[q[i]]
                else:
                    if q[i] == 1:
                        # 编号为1的牛说明当前的j就是编号为1的牛的位置
                        return j
                    else:
                        st[j] = 1
                        j += 1
        else:
            # 说明编号为1的牛不在m中那么就需要从后往前放置m头牛, 与第二种情况是类似的
            j = n
            for i in range(m - 1, -1, -1):
                while st[j] == 1: j -= 1
                # 当前编号为q[i]已经有固定位置了那么就不用放置了更新一下j
                if p[q[i]] != -1:
                    j = p[q[i]]
                else:
                    st[j] = 1
                    j -= 1
            # 从前往后遍历第一个没有被占用的位置就是编号为1的牛的位置
            for i in range(1, n + 1):
                if st[i] == 0: return i


if __name__ == "__main__":
    print(Solution().process())
举报

相关推荐

0 条评论