算法-图是否为树(并查集或深搜)

今天做了一道很有意思的一道题,这道题虽然难度只是中等,但是里面涉及到的东西却是不少。其中,我在里面学习到了并查集这个东西,虽然不是很深刻,至少有一个印象;还有深搜,一直以来,深搜和广搜都是我的弱项,本文的理解是基于别人的博客:lintcode178. graph valid tree 图是否是树。我们来看看题

题意:

给出 n 个节点,标号分别从 0 到 n - 1 并且给出一个 无向 边的列表 (给出每
条边的两个顶点), 写一个函数去判断这张`无向`图是否是一棵树

样例:

给出n = 5 并且 edges = [[0, 1], [0, 2], [0, 3], [1, 4]], 返回 true.

给出n = 5 并且 edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], 返回 false.

注意事项:

你可以假设我们不会给出重复的边在边的列表当中. 无向边 [0, 1] 和 [1, 0] 
是同一条边, 因此他们不会同时出现在我们给你的边的列表当中。

1.并查集

首先有两点:

  A.如果点的个数减去边数不等于1,此图肯定不为树。

  B.如果有一条边的两个点同属于一个集合的话,那么此图肯定不为树

第一点我们非常容易的能够判断出来,但是第二种怎么来判断呢?这就需要我们的并查集(我也是第一次接触到并查集,只是知道它的模型,所以可能说的不是很清楚)。

(1).一维数组记录每一个点的集合

我们首先可以定义一个一维数组,默认全部初始化为-1,其中表示的意思就是:假设数组temp[], temp[0]表示的是0这个点属于的集合,不同的集合我们不同数字来表示,比如,0集合和1集合是不同的,同一个集合的点构成了一棵树。

具体的操作:

当我们遍历到一条边时,判断这条边的两个点是否在temp数组中出现,其中分为三种情况:

A.两个点均未出现,也就是两个点对应的temp数组的值是等于-1,那么,我们将这两个点对应的数组值更为两点中最小的那个点(这里没有限制,最大也行,主要是保证他们俩在同一个集合中)。

B.一个点出现过,一个点未出现,那么我们将未出现的那个点对应的数组值更新为出现的那个点的数组值,这样就保证了两个点属于同一个集合。

C.两个点都出现过,只是属于不同的集合,也就是说,两个点对应的数组值不相同,那么此时我们的操作是将两个集合合并起来,具体的操作是:因为每个集合里面的所有值都是相同,那么我们将值较大的那个集合的值全部更新为另一个集合的值,比如有两个集合分别是:{1,1},{2,2},更新过后就是:{1,1,1,1}。这样能保证两个集合合并起来后,构成一个集合。

D.两个点都出现过,同时还属于同一个集合,那么此图肯定不为树。

代码:

 1     public boolean validTree(int n, int[][] edges) {
 2         //当点数减去边数不等于1时,肯定不为树
 3         if (n - edges.length != 1) {
 4             return false;
 5         }
 6         int temp[] = new int[n];
 7         for (int i = 0; i < edges.length; i++) {
 8             int node1 = edges[i][0];
 9             int node2 = edges[i][1];
10             // 当两个点属于同一个集合时,要么两点没有在任何集合里面,要么在同一个集合里面
11             if (temp[node1] == temp[node2]) {
12                 //都没有出现过
13                 if (temp[node1] == -1) {
14                     temp[node1] = temp[node2] = Math.min(node1, node2);
15                 } else { //都出现过,同时还属于同一个集合
16                     return false;
17                 }
18             } else {
19                 // 当两个点都在集合里面,但是是在不同的集合里,更新集合
20                 if (temp[node1] != -1 && temp[node2] != -1) {
21                     int max = Math.max(temp[node1], temp[node2]);
22                     int min = Math.min(temp[node1], temp[node2]);
23                     for (int j = 0; j < n; j++) {
24                         if (temp[j] == max) { //将值较大的集合的值全部更新min
25                             temp[j] = min;
26                         }
27                     }
28                 } else { // 当只有一个点在集合里面
29                     if (temp[node1] != -1) {
30                         temp[node2] = temp[node1];
31                     } else {
32                         temp[node1] = temp[node2];
33                     }
34                 }
35             }
36         }
37         return true;
38     }

如图所示:

2.深搜遍历

深搜遍历在这里主要作用是:我们寻找每一个点的父节点,如果两个点的父节点相同的话,那么此图肯定不为树。这里的理解上可能有一些问题,我们看看下面的几种情况:

 (1).两个点均是第一次出现。如图:

(2).一个点是出现过的,另一个点是第一次出现。如图(提示一下,下面图的描述错了,C的父亲应该是A):

(3).两个点都有父亲,只是父亲不相同,分为两种情况:

  (4).两个点都出现过,并且父亲相同,分为两种情况:

代码:

 1     private int dfs(int temp[], int node){
 2         //当这个点不在有父亲了,返回这个点
 3         if(temp[node] == -1){
 4             return node;
 5         }
 6         else //如果这点还有父亲的话,那么就继续遍历这个点的父亲
 7         {
 8             return dfs(temp, temp[node]);
 9         }
10     }
11     public boolean validTree(int n, int[][] edges) {
12
13         if (n - edges.length != 1) {
14             return false;
15         }
16         int []temp = new int[n];
17         Arrays.fill(temp,-1);
18         for(int i = 0; i < edges.length; i++){
19             //获取edges[i][0]点的父亲
20             int node1 = dfs(temp, edges[i][0]);
21             //获取edges[i][1]点的父亲
22             int node2 = dfs(temp, edges[i][0]);
23             //如果父亲相同的话,肯定不为树
24             if(node1 == node2){
25                 return false;
26             }
27             //将node2的父亲设置为node1
28             temp[node2] = node1;
29         }
30         return true;
31     }
时间: 2024-10-09 20:48:34

算法-图是否为树(并查集或深搜)的相关文章

poj2513Colored Sticks(欧拉通路+字典树+并查集)

Description You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sticks in a straight line such that the colors of the endpoints that touch are of the same color? Input Input is a

UVALive 4730 Kingdom 线段树+并查集

题目链接:点击打开链接 题意见白书P248 思路: 先把读入的y值都扩大2倍变成整数 然后离散化一下 用线段树来维护y轴 区间上每个点的 城市数量和联通块数量, 然后用并查集维护每个联通块及联通块的最大最小y值,还要加并查集的秩来记录每个联通块的点数 然后就是模拟搞.. T^T绝杀失败题..似乎数组开小了一点就过了,== #include<stdio.h> #include<math.h> #include<vector> #include<string.h>

UVA 1455 - Kingdom(线段树+并查集)

UVA 1455 - Kingdom 题目链接 题意:给定一些城市坐标点,连在一起的城市称为一个州,现在用两种操作,road表示把城市a,b建一条路,line表示询问一个y轴上穿过多少个州,和这些州共包含多少个城市 思路:利用并查集维护每个州的上界和下界还有城市个数,然后每次加进一条路的时候,根据两个集合的位置可以处理出区间的州和城市数如何进行加减,然后利用线段树搞就可以了 代码: #include <cstdio> #include <cstring> #include <

POJ 2513 Colored Sticks(字典树+并查集连通性+欧拉回路)

题目地址:POJ 2513 刚开始没想到字典树,用的map函数一直TLE,由于上一次的签到题由于没想到字典树而卡了好长时间的深刻教训,于是过了不久就想起来用字典树了,(为什么是在TLE了5次之后..T^T)然后把map改成了字典树,然后就过了. 这题居然不知不觉的用上了欧拉回路..其实当时我是这样想的..因为相互接触的必须要相同,所以除了两端外,其他的都是两两相同的,所以除了两端的颜色外其他的的个数必须为偶数.然后两端的可能相同可能不相同,相同的话,说明所有的都是偶数个数了,不相同的话那就只有这

POJ-2513 Colored Sticks(字典树+并查集+欧拉)

题目链接:Colored Sticks 一道3个知识点结合的题目,可以说单个知识点的题目,都会做,一旦知识点结合起来,题目就不简单了 思路:这个题开始看就知道是并查集,但是不好处理的不同种单词的统计,所以理所应当联想到字典树,上次做字典树的题目啸爷出的是统计相同单词数,这个题目和那个一样,把flag加个编号即可,再利用并查集. 1750ms  水过 #include <iostream> #include <cstdio> #include <cstdlib> #inc

模板 - 左偏树 + 并查集

这两个经常混在一起用的样子,封成同一个好了. #include<bits/stdc++.h> using namespace std; typedef long long ll; int solve(); int main() { #ifdef Yinku freopen("Yinku.in","r",stdin); #endif // Yinku solve(); } int n,m; const int MAXN=100005; int tot,v[

POJ 2513 Colored Sticks(欧拉道路+字典树+并查集)

http://poj.org/problem?id=2513 题意: 给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的. 思路: 题目很明显的是欧拉道路的问题. 欧拉道路的关键是: ①图是连通的. ②最多只能有两个奇点.(不能只存在一个奇点) 本来是想用map映射的,但是太多了,比较费时,这里用字典树的话会比较省时,判断图是否连通可以用并查集来完成. 1 #include<iostream> 2 #include<algori

【BZOJ4551】[Tjoi2016&amp;Heoi2016]树 并查集

[BZOJ4551][Tjoi2016&Heoi2016]树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个 结点,可以打多次标记.)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖 先)你能帮帮他吗? Input 输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行

poj2513 Colored Sticks (欧拉通路+Trie树+并查集)

D - Colored Sticks Crawling in process... Crawling failed Time Limit:5000MS     Memory Limit:128000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2513 Appoint description: System Crawler (2016-05-05) Description You are given a bunch