测试一个图是否是树
Testing whether a graph is a tree
输入规范N给出节点个数,M给出边个数。第一个简单的检验是M应该等于N-1否则它就不可能是树。
我接下来做的只是一个DFS,我看到在DFS期间,我们是否再次遇到访问过的节点(与父节点不同,这里的父节点是指调用相邻节点的DFS的节点),那么这意味着我们有一个循环,它不是树。但显然我的解决方案总是得到错误的答案。我张贴的代码,但只有片段是重要的。我将图存储为邻接表,并发布函数isTree()
来测试它是否是树?正确的逻辑是什么?
#include <iostream>
#include <list>
using namespace std;
// Graph class represents a directed graph using adjacency list representation
class Graph
{
int V; // No. of vertices
list<int> *adj; // Pointer to an array containing adjacency lists
bool isTreeUtil(int v, bool visited[],int parent);
public:
Graph(int V); // Constructor
void addEdge(int v, int w); // function to add an edge to graph
bool isTree(); // Tells whether the given graph is a tree or not
void printGraph();
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V+1];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w); // Add w to v’s list.
adj[w].push_back(v);
}
bool Graph::isTreeUtil(int v, bool visited[],int parent)
{
//int s_v = v;
visited[v] = true;
list<int>::iterator i;
for(i = adj[v].begin(); i != adj[v].end(); ++i) {
if (!visited[*i])
isTreeUtil(*i,visited,v);
else {
if (*i != parent && visited[*i])
return false;
}
}
return true;
}
bool Graph::isTree() {
bool *visited = new bool[V+1];
for(int i = 1; i < V+1; i++)
visited[i] = false;
visited[1] = true; // marking the first node as visited
for(int i = 1; i < V+1; i++)
visited[i] = false;
int parent = -1; // initially it has no parent
//list<int> :: iterator i;
//for (i = adj[v].begin(); i != adj[v].end(); ++i)
return isTreeUtil(1, visited, parent);
}
void Graph::printGraph() {
for (int i = 1;i <= this->V; i++) {
cout << i << "->";
list<int>::iterator j;
for (j = adj[i].begin(); j != adj[i].end(); ++j) {
cout << *j << "->";
}
cout << "n";
}
}
int main() {
int N, M;
cin >> N >> M;
Graph G(N);
int v, w;
int m = 0;
while (m < M) {
cin >> v >> w;
G.addEdge(v,w);
m++;
}
if (M != N-1) {
cout << "NOn";
else if (G.isTree())
cout << "YESn";
else
cout << "NOn";
}
我编译了你的代码,并在我的机器上运行。在实现图形时,需要考虑一些重要的规范。当您选择遵守规范时,在代码中强制执行该规范通常是一种好做法。
图有双向边已经很清楚了,尽管特别提到这一点也无妨。
允许重复边?你的程序允许我先画一条边(1,2)然后再画一条边(1,2)然后算为两条边。这使得条件M != N-1
成为一个不充分的检查。要么禁止重复的边,要么在你的算法中考虑它们(目前,重复的边会导致你的算法返回不正确)。
自我边缘?你的图允许顶点有自己的边吗?如果是这样,自路径是否应该使树失效(也许自循环是合法的,因为在树中,每个节点都可以访问自己)?目前,self边也会破坏你的算法。
为了帮助你,这里是我修改的addEdge()的实现,它禁止重复的边和禁止自循环。作为奖励,它还检查数组边界;)请注意附加的include和函数签名的变化(它现在返回bool值)。
#include <algorithm>
bool Graph::addEdge(int v, int w)
{
// sanity check to keep us from seg faulting
if (v < 1 || v > this->V || w < 1 || w > this->V) {
return false;
}
// no self-edges
if (w == v) {
return false;
}
// no duplicate edges allowed either
std::list<int>::iterator findV = std::find(adj[v].begin(), adj[v].end(), w);
std::list<int>::iterator findW = std::find(adj[w].begin(), adj[w].end(), v);
if (findV != adj[v].end() || findW != adj[w].end()) {
return false;
}
adj[v].push_back(w); // Add w to v’s list.
adj[w].push_back(v);
return true;
}
我希望这对你有帮助。如果这是一项作业,你应该复习一下文章。如果您的实现是自动分级的,他们必须指定这些情况。正如@congusbongus所提到的,你的算法在节点断开连接的情况下也会失败。
请注意,您还必须修改main()
方法,以便我的实现工作。修改函数的这一部分:
while (m < M) {
cout << "Create Edge from x to y" << endl;
cin >> v >> w;
if (!G.addEdge(v,w)) {
cout << ">>Invalid edge not added" << endl;
} else {
cout << ">>Successfully added edge" << endl;
m++;
}
}
它可以运行我在纸上画的所有简单的测试用例,但是当提交时它失败了!
听起来像是家庭作业的自动评分系统,对吗?如果您可以访问准确的测试用例,那么问题将是显而易见的。在这种情况下,它可能是不可用的,所以我们只能推测。
根据我的经验,大多数这类失败都是由于错过了边界情况。你说你检查边数=节点数- 1,但你也考虑过以下几点吗?
- 所有节点已连接
- 每对节点不超过一条边
也就是说,你的程序是否准备为此返回"NO"?
_
/
o o---o
Nodes: 3, edges: 2
- 是否有必要使用 std::move?这不是已经是一个右值参考了吗?
- 如何检查一个模板是否是另一个模板的类成员
- 是否存在一个范围::视图::group_by对应项,它将所有元素都考虑在内,而不是只考虑连续的元素
- 如何检查字符串中的最后一个字符是否是某个字符并将其从字符串中删除?(C++)
- 当 map 是一个整数数组并且由 operator[] 创建时,它是否初始化其映射类型
- 如何以更有效的方式检查一个数字是否是素数?
- 检查C++中是否只有一个字符串变量不是 nullptr
- 检查数值类型是否是另一个数值类型的子集
- isdigit() 和 isalnum() 给出错误,因为输入是一个常量字符并且无法转换。其他可能查看输入是否为数字的方法?
- 如何判断变量是否是一个复杂的数字C
- r语言 - 在C++中使用 RCPP 的 NumericMatrix 循环是否是一个好的理想?
- 我正在尝试做一个循环,检查输入是否是一个数字,如果没有再次询问
- 使用 "-g" 标志进行生产是否是一个好主意?
- 如何确定整个图是否是一个强连接的组件
- 有没有办法检查一个变量是否是一个整数?C++
- 我如何创建一个循环来检查用户的输入,看看它是否是一个现有的文件
- 有人能确认一下这是否是一个线程安全的单例实现吗?
- 如何写一个字符串,看看它是否是一个表达式
- 是否是一个临时的l值
- 我如何检查输入是否是一个int在c++