4084 号码牌(并查集)
1. 問題描述:
有 n 個小朋友,編號 1~n。每個小朋友都拿著一個號碼牌,初始時,每個小朋友拿的號碼牌上的號碼都等于其編號。每個小朋友都有一個幸運數字,第 i 個小朋友的幸運數字為 di。對于第 i 個小朋友,他可以向第 j 個小朋友發起交換號碼牌的請求,當且僅當 |i ? j| = di 成立。注意,請求一旦發出,對方無法拒絕,只能立刻進行交換。每個小朋友都可以在任意時刻發起任意多次交換請求。給定一個 1~n 的排列 a1,a2,…,an。請問,通過小朋友相互之間交換號碼牌,能否使得第 i 個小朋友拿的號碼牌上的號碼恰好為 ai,對 i∈[1,n] 均成立。
輸入格式
第一行包含整數 n。第二行包含 n 個整數 a1,a2,…,an。第三行包含 n 個整數 d1,d2,…,dn。
輸出格式
共一行,如果能做到,則輸出 YES,否則輸出 NO。
數據范圍
前 6 個測試點滿足 1 ≤ n ≤ 10。
所有測試點滿足 1 ≤ n ≤ 100,1 ≤ di ≤ n,保證 a1~an 是一個 1~n 的排列。
輸入樣例1:
5
5 4 3 2 1
1 1 1 1 1
輸出樣例1:
YES
輸入樣例2:
7
4 3 5 1 2 7 6
4 6 6 1 6 6 1
輸出樣例2:
NO
輸入樣例3:
7
4 2 5 1 3 7 6
4 6 6 1 6 6 1
輸出樣例3:
YES
來源:https://www.acwing.com/problem/content/4087/
2. 思路分析:
分析題目可以知道每一個小朋友在滿足可以交換的條件下可以進行交換的操作,并且可以發現交換具有傳遞性,例如A可以和B交換,B可以和C交換,那么A可以和C交換,進而A,B,C之間可以任意交換,相互交互在圖論上屬于一個連通塊,相當于一棵樹的形式,也即在同一個集合中的所有元素是可以任意交換的,不在同一個集合中的元素不能夠交換,根據這個特點可以知道我們需要合并同一個集合中的所有元素,而合并集合中的元素可以使用并查集進行合并,所以這道題目考察的是并查集的相關操作,由于一開始的時候i = ai,所以我們可以從1枚舉到n,將當前節點合并到它所在的集合中,聲明A,B分別記錄集合中已經有牌的集合和需要的牌的集合,從1枚舉到n,枚舉的過程中通過并查集的find操作找到當前的節點i所在的集合,當前節點i所在的集合A[find(i)]加上當前的節點i,當前節點i所在的集合B[find(i)]加上a[i]表示當前集合需要a[i]這個元素,最終判斷A和B中每一個集合的元素是否相同即可。
3. 代碼如下:
from typing import Listclass Solution:def find(self, x: int, fa: List[int]):if x != fa[x]: fa[x] = self.find(fa[x], fa)return fa[x]def merge(self, a: int, b: int, n: int, fa: List[int]):# 越界了所以需要跳過if b < 1 or b > n: return# 合并a, b兩個節點為同一個集合fa[self.find(a, fa)] = self.find(b, fa)# 并查集def process(self):n = int(input())a = [0] + list(map(int, input().split()))d = [0] + list(map(int, input().split()))fa = [i for i in range(n + 10)]for i in range(1, n + 1):# 合并屬于同一個集合中的所有點self.merge(i, i - d[i], n, fa)self.merge(i, i + d[i], n, fa)# A為當前已有牌的集合, B為需要的牌的集合A, B = [list() for i in range(n + 10)], [list() for i in range(n + 10)]for i in range(1, n + 1):# 合并每一個節點屬于哪一個集合A[self.find(i, fa)].append(i)B[self.find(i, fa)].append(a[i])# A是有序的但是B不是有序的所以需要對每一個B[i]進行排序for i in range(1, n + 1):if B[i]:# 從小到大進行排序B[i].sort()# 判斷兩個集合是否相等, python直接判斷相等即可for i in range(1, n + 1):if A[i] != B[i]:print("NO")returnprint("YES")if __name__ == "__main__":Solution().process()總結
以上是生活随笔為你收集整理的4084 号码牌(并查集)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win10开启黑色护眼暗黑主题
- 下一篇: 硬件行业知识体系概要 转载