Is It A Tree?(并查集)(dfs也可以解决)
Description
There is exactly one node, called the root, to which no directed edges point.
Every node except the root has exactly one edge pointing to it.
There is a unique sequence of directed edges from the root to each node.
For example, consider the illustrations below, in which nodes are represented by circles and edges are represented by lines with arrowheads. The first two of these are trees, but the last is not.
In this problem you will be given several descriptions of collections of nodes connected by directed edges. For each of these you are to determine if the collection satisfies the definition of a tree or not.
Input
Output
Sample Input
6 8 5 3 5 2 6 4
5 6 0 0 8 1 7 3 6 2 8 9 7 5
7 4 7 8 7 6 0 0 3 8 6 8 6 4
5 3 5 6 5 2 0 0
-1 -1
Sample Output
Case 1 is a tree.
Case 2 is a tree.
Case 3 is not a tree. 题意:给定一定关系,判断其是否是一棵树,注意,空树也是一棵树,不能有成环的情况,不能是森林,不能有入度为2的节点。
下面给出两种思路:
1,并查集:维护一个森林 每输入一组关系(边)的时候,将这两个点连起来看做一棵树,如果可以将其合并到其他的树上的话就将其合并,并且树的总数目加1;
(注意: 只有当第二个端点值在其他树上是根节点的时候才能合并仍保持是一棵树,及从第一个端点指向第二个端点的时候会保证不会出现入度为2的点)
如果不满足合并条件的时候就将定义的树的总数加1,中间过程有可能再将这两棵树连起来,所有操作完成后,统计树的个数,要是树的棵树大于1的话则所给点不能构成一棵树
注意要排除自成环的情况,和空树的情况。
2,dfs:
将所有的边用链接表的方式存起来,当按照正常的顺序扫描一遍的时候如果是一个符合条件的树的话就不会存在一个点被访问两次,即扫描的时候不会出现visit数组被标记为走过的情况
而且当以任一点为开始扫描完一遍的时候不存在没有扫描过的点,因为不存在森林。
这里同样要考虑空树的情况。
/**
---------------------------------------------------
HuHanwu
2012-7-12
并查集快速判断每次输入是破坏树的性质
时间复杂度: o(n) n为节点的个数
---------------------------------------------------
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define MAXN 1000002 int p[MAXN]; //存放父亲节点 只要存在父亲节点则此节点一存在某棵树中
int find(int x){ return p[x]==x ? x :(p[x]=find(p[x]));} //查找父亲节点并 压缩路径 int main()
{
int a,b,tree_num,t=,father_a,father_b,TF; //tree_num 保存当前的树的棵数
while(~scanf("%d%d",&a,&b) && (a>=||b>=))
{
tree_num=TF=;
if(a==)
{
printf("Case %d is a tree.\n",++t);
continue;
}//空树也是一棵树
if(a==b)
TF=;//不能成环
else
{
memset(p,,sizeof(p)); //用 0 初始化所有节点的父亲节点
p[a]=p[b]=a;
}
while(~scanf("%d%d",&a,&b) && a!=)
{
if(TF== ) // 只要已经判断出该森林已经不是树
continue;
if(p[b]!=) // b节点已经存在
{
father_b=find(b);
if(b!=father_b) // b 节点不是树根就不可以连成一棵树
{
TF=;
continue;
}
else//下面都是当b 为树根的情况
{
if(p[a]!=) // a b 节点都存在则树的的棵数-1
{
p[b]=find(a);//将两棵树连起来,只有当b是父节点的时候才可以这么连
tree_num--;
}
else //a 节点不存在 而 b 节点存在
p[b]=p[a]=a;
}
}
else
{
if(p[a]==) // a b 节点都不存在则树的棵数+1
{
p[a]=p[b]=a;
tree_num++;
}
else //a 节点存在 而 b 节点不存在
p[b]=find(a);
}
}
printf("Case %d ",++t);
if(TF==)
{
printf("is not a tree.\n");
continue;
}
if(tree_num==) // 树的棵数是否为1
printf("is a tree.\n");
else
printf("is not a tree.\n");
}
return ;
}
下面给出dfs代码,其中用链表存放边
#include <cstdio>
#include <map>
#include <cstring>
using namespace std;
#define N 50005 int head[N];
struct Edge{
int v, next;
}edge[N*];
int Ecnt; void init()
{
Ecnt = ;
memset(head, -, sizeof(head));
} void add(int u, int v)
{
edge[Ecnt].v = v;
edge[Ecnt].next = head[u];
head[u] = Ecnt++;
} bool visited[N];
bool dfs(int u)
{
for(int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].v;
if(visited[v]) return false;
visited[v] = ;
int res = dfs(v);
if(res == false) return false;
}
return true;
} struct Node {
int s, t;
}node[N]; map<int, int>mp; int in[N];
int main()
{
int s, t, cas = ;
while(~scanf("%d %d", &s, &t))
{
cas++;
if(s == && t == ){
printf("Case %d is a tree.\n", cas);
continue;
}
if(s < && t < ) break;
int c = ;
node[c].s = s, node[c++].t = t;
while(~scanf("%d %d", &s, &t), s||t)
node[c].s = s, node[c++].t = t; mp.clear();
int n = ;//结点总数
for(int i = ; i < c; i++)
{
s = node[i].s, t = node[i].t;
if(mp.find(s) == mp.end()) mp[s] = n++;
if(mp.find(t) == mp.end()) mp[t] = n++;
node[i].s = mp[s];
node[i].t = mp[t];
}
init();
memset(in, , sizeof(in));
for(int i = ; i < c; i++)
{
s = node[i].s, t = node[i].t;
add(s, t);
in[t]++;
}
bool ans = true;
int root = -;
for(int i = ; i < n; i++)
{
if(in[i] == )
{
if(root == -) root = i;
else ans = false;
}
}
if(ans == false || root == -)
{
printf("Case %d is not a tree.\n", cas);
ans = false;
continue;
}
memset(visited, , sizeof(visited));
visited[root] = ;
ans = dfs(root);
if(ans == false)
{
printf("Case %d is not a tree.\n", cas);
ans = false;
continue;
}
for(int i = ; i < n; i++)
if(!visited[i])
{
printf("Case %d is not a tree.\n", cas);
ans = false;
break;
}
if(ans)printf("Case %d is a tree.\n", cas);
}
}
Is It A Tree?(并查集)(dfs也可以解决)的更多相关文章
- F2 - Spanning Tree with One Fixed Degree - 并查集+DFS
这道题还是非常有意思的,题意很简单,就是给定一个图,和图上的双向边,要求1号节点的度(连接边的条数)等于K,求这棵树的生成树. 我们首先要解决,如何让1号节点的度时为k的呢???而且求的是生成树,意思 ...
- 第46届ICPC澳门站 K - Link-Cut Tree // 贪心 + 并查集 + DFS
原题链接:K-Link-Cut Tree_第46屆ICPC 東亞洲區域賽(澳門)(正式賽) (nowcoder.com) 题意: 要求一个边权值总和最小的环,并从小到大输出边权值(2的次幂):若不存在 ...
- 1021.Deepest Root (并查集+DFS树的深度)
A graph which is connected and acyclic can be considered a tree. The height of the tree depends on t ...
- 树上统计treecnt(dsu on tree 并查集 正难则反)
题目链接 dalao们怎么都写的线段树合并啊.. dsu跑的好慢. \(Description\) 给定一棵\(n(n\leq 10^5)\)个点的树. 定义\(Tree[L,R]\)表示为了使得\( ...
- Codeforces_764_C. Timofey and a tree_(并查集)(dfs)
C. Timofey and a tree time limit per test 2 seconds memory limit per test 256 megabytes input standa ...
- Hdu.1325.Is It A Tree?(并查集)
Is It A Tree? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...
- HDU 1232 并查集/dfs
原题: http://acm.hdu.edu.cn/showproblem.php?pid=1232 我的第一道并查集题目,刚刚学会,我是照着<啊哈算法>这本书学会的,感觉非常通俗易懂,另 ...
- Is It A Tree?(并查集)
Is It A Tree? Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 26002 Accepted: 8879 De ...
- CF109 C. Lucky Tree 并查集
Petya loves lucky numbers. We all know that lucky numbers are the positive integers whose decimal re ...
随机推荐
- C:函数:功能:实现字符数组中所有字母的倒序存放并输出
前两天小测碰到一道题,建立一个函数,功能:实现字符数组中所有字母的倒序存放并输出,一开始觉得简单跟数字数组差不多,运行一下发现很多格式错误,这些是不必要的错误,现在就来说下,先说一下代码思路:定义一个 ...
- Java I/O---Reader & Writer(字符流)
1.Reader & Writer 当我们初次看见Reader和Writer类时,可能会以为这是两个用来替代InputStream和OutputStreamt的类,但实际上并非如此. 尽管一些 ...
- arcgis api for js热力图优化篇-不依赖地图服务
前面我写过一篇文章,介绍如何实现arcgis api的热力图效果,但是依赖arcgis server发布的地图服务来获取热力图的数据源.实际应用中,很多业务数据来源数据库,并不一定是从地图服务来获取的 ...
- bzoj 3718: [PA2014]Parking
Description 你的老板命令你将停车场里的车移动成他想要的样子. 停车场是一个长条矩形,宽度为w.我们以其左下角顶点为原点,坐标轴平行于矩形的边,建立直角坐标系.停车场很长,我们可以认为它一直 ...
- vue入坑总结
1.Do not mount Vue to <html> or <body> - mount to normal elements instead. Vue2.x之后不推荐挂载 ...
- KVM(二):KVM应用
++++++++++++++++++++++++++++++创建和拍摄快照++++++++++++++++++++++++++++++++++ KVM快照方法常用的是qemu-img snapshot ...
- css scroll bug
滚动区域不能设置overflow var doc = $(document), win = $(window), h = $("#head"), b = $("#body ...
- Django__Ready
Python WEB框架 : DJango : 大而全 flask : 小而精 tornado : 下载DJango : PIP3 INSTALL DJANGO 创建DJango项目 : django ...
- Head First设计模式之生成器模式
一.定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.建造者模式是一种对象创建型模式. 二.结构 角色 Builder(抽象建造者):它为创建一个产品Product对象的 ...
- Java的按位操作符
本文参考:Java的位操作符 Java的位操作符用来操作整数基本数据类型中的单个"比特"(bit),即代进制位.而我们知道比特就是0和1,那么,位操作就是对这些数据进行基本的操作. ...