本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、题目描述:
1042. 不邻接植花 - 力扣(LeetCode) (leetcode-cn.com)
有 n 个花园,按从 1 到 n 标记。另有数组 paths ,其中 paths[i] = [xi, yi] 描述了花园 xi 到花园 yi 的双向路径。在每个花园中,你打算种下四种花之一。
另外,所有花园 最多 有 3 条路径可以进入或离开.
你需要为每个花园选择一种花,使得通过路径相连的任何两个花园中的花的种类互不相同。
以数组形式返回 任一 可行的方案作为答案 answer,其中 answer[i] 为在第 (i+1) 个花园中种植的花的种类。花的种类用 1、2、3、4 表示。保证存在答案。
示例 1:
输入:n = 3, paths = [[1,2],[2,3],[3,1]]
输出:[1,2,3]
解释:
花园 1 和 2 花的种类不同。
花园 2 和 3 花的种类不同。
花园 3 和 1 花的种类不同。
因此,[1,2,3] 是一个满足题意的答案。其他满足题意的答案有 [1,2,4]、[1,4,2] 和 [3,2,1]
示例 2:
输入:n = 4, paths = [[1,2],[3,4]]
输出:[1,2,1,2]
示例 3:
输入:n = 4, paths = [[1,2],[2,3],[3,4],[4,1],[1,3],[2,4]]
输出:[1,2,3,4]
提示:
- 1 <= n <= 10^4
- 0 <= paths.length <= 2 * 10^4
- paths[i].length == 2
- 1 <= xi, yi <= n
- xi != yi
- 每个花园 最多 有 3 条路径可以进入或离开
二、思路分析:
用一个二维容器g作为邻接表,由所给的路径paths构建,从第1个花园开始,进行深度优先搜索,对已经访问的结点作标记,然后遍历与该结点相邻接的点,比较它们各自种植花的种类(一开始默认为0,表示还没种),然后从小到大找出暂未种植的花作为正在访问结点的种植对象,之后一直递归下去。
注意到并非所有花园一定连通,因此在主要方法中需要对每个暂未访问的结点进行以上的深度优先搜索,最终便可得到每个花园的种植种类。
三、AC 代码:
class Solution {
public:
vector<vector<int>> g;
vector<int> ret;
vector<bool> visited;
void dfs(int n){
visited[n] = true; //标记为访问
vector<int> counts(5,0);
for (const auto& node:g[n]){
counts[ret[node-1]]++;
}
for (int i=1; i<=4; ++i) //选一种花
if(counts[i] == 0){
ret[n-1] = i;
break;
}
for (const auto& node:g[n]){
if(!visited[node])
dfs(node);
}
}
vector<int> gardenNoAdj(int N, vector<vector<int>>& paths) {
g = vector<vector<int>>(N+1);
for (int i=0; i<paths.size(); ++i){
g[paths[i][0]].push_back(paths[i][1]);
g[paths[i][1]].push_back(paths[i][0]);
}
visited = vector<bool>(N+1, 0);
ret = vector<int>(N, 0);
for (int i=1; i<=N; ++i){
if(!visited[i])
dfs(i);
}
return ret;
}
};