树结构判定
描述
给定一个包含 N 个顶点 M 条边的无向图 G ,判断 G 是不是一棵树。
输入
第一个是一个整数 T ,代表测试数据的组数。 (1 ≤ T ≤ 10)
每组测试数据第一行包含两个整数 N 和 M 。(2 ≤ N ≤ 500, 1 ≤ M ≤ 100000)
以下 M 行每行包含两个整数 a 和 b ,表示顶点 a 和顶点 b 之间有一条边。(1 ≤ a, b ≤ N)
输出
对于每组数据,输出YES或者NO表示 G 是否是一棵树。
分析:
用并查集判断所有节点的父节点是否是一个,如果是那么就是一棵树,否则不是树形结构。
官方题解:
本题要求判断给定的无向图是不是一棵树。
包含N个点M条边的无向图是树的充分必要条件是N=M+1且N个点连通。
所以本题的关键就是判断这N个点是不是连通在一起。
判断连通性一般也有两种方法。
一种是从一个点(比如1号点)开始进行DFS/BFS,搜索过程中把遇到的点都标记上,最后检查是不是N个点都被标记了。
另一种方法是用并查集,依次处理每一条边,把每条边的两个顶点都合并到一个集合里。最后检查是不是N个点都在同一个集合中。
并查集算法可以参考 hiho一下第14周 的提示。
AC代码:
//并查集
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int ma=510;
int fa[ma];
int findfa(int x)
{
if(x==fa[x]) return x;
return fa[x]=findfa(fa[x]);
}
int main()
{
int t;
scanf("%d",&t);
int n,m;
while(t--)
{
scanf("%d%d",&n,&m);
bool fg=false;
if(m!=n-1) fg=true;
for(int i=1;i<=n;++i) fa[i]=i;
int x,y;
while(m--)
{
scanf("%d%d",&x,&y);
int fx=findfa(x),fy=findfa(y);
if(fa[fx]!=fa[fy])
fa[fx]=fa[fy];
}
if(fg)
{
printf("NO\n");
continue;
}
int root=findfa(fa[1]);
for(int i=2;i<=n;++i)
if(findfa(fa[i])!=root)
{
fg=true;
break;
}
if(fg) printf("NO\n");
else printf("YES\n");
}
return 0;
}
//DFS,这里用的是链表型的数据结构
#include <stdio.h>
#include <string.h>
struct _adj
{
int v ;
int next ;
} ;
struct _adj adj[205000] ;
bool visited[510] ;
int solve( int u, int parent )
{
visited[u] = true ;
int p = adj[u].next ;
int ret = 1 ;
while ( p != -1 )
{
if ( adj[p].v == parent )
{
p = adj[p].next ;
continue ;
}
if ( visited[ adj[p].v ] )
return 0 ;
int tmp = solve( adj[p].v, u ) ;
if ( tmp == 0 )
return 0 ;
else
ret += tmp ;
p = adj[p].next ;
}
return ret ;
}
int main()
{
int t ;
int n, m ;
int i, j, k ;
int adjused ;
scanf( "%d", &t ) ;
while ( t-- )
{
scanf( "%d %d", &n, &m ) ;
adjused = n ;
if ( m != n - 1 )
{
for ( k = 0 ; k < m ; ++k )
scanf( "%d %d", &i, &j ) ;
printf( "NO\n" ) ;
continue ;
}
for ( i = 0 ; i < n ; ++i )
adj[i].next = -1 ;
for ( k = 0 ; k < m ; ++k )
{
scanf( "%d %d", &i, &j ) ;
--i ; --j ;
adj[ adjused ].v = j ;
adj[ adjused ].next = adj[i].next ;
adj[i].next = adjused ;
++adjused ;
adj[ adjused ].v = i ;
adj[ adjused ].next = adj[j].next ;
adj[j].next = adjused ;
++adjused ;
}
memset( visited, false, sizeof( visited ) ) ;
if ( solve( 0, -1 ) != n )
printf( "NO\n" ) ;
else
printf( "YES\n" ) ;
}
return 0 ;
}
#include <stdio.h>
#include <string.h>
struct _adj
{
int v ;
int next ;
} ;
struct _adj adj[205000] ;
bool visited[510] ;
int solve( int u, int parent )
{
visited[u] = true ;
int p = adj[u].next ;
int ret = 1 ;
while ( p != -1 )
{
if ( adj[p].v == parent )
{
p = adj[p].next ;
continue ;
}
if ( visited[ adj[p].v ] )
return 0 ;
int tmp = solve( adj[p].v, u ) ;
if ( tmp == 0 )
return 0 ;
else
ret += tmp ;
p = adj[p].next ;
}
return ret ;
}
int main()
{
int t ;
int n, m ;
int i, j, k ;
int adjused ;
scanf( "%d", &t ) ;
while ( t-- )
{
scanf( "%d %d", &n, &m ) ;
adjused = n ;
if ( m != n - 1 )
{
for ( k = 0 ; k < m ; ++k )
scanf( "%d %d", &i, &j ) ;
printf( "NO\n" ) ;
continue ;
}
for ( i = 0 ; i < n ; ++i )
adj[i].next = -1 ;
for ( k = 0 ; k < m ; ++k )
{
scanf( "%d %d", &i, &j ) ;
--i ; --j ;
adj[ adjused ].v = j ;
adj[ adjused ].next = adj[i].next ;
adj[i].next = adjused ;
++adjused ;
adj[ adjused ].v = i ;
adj[ adjused ].next = adj[j].next ;
adj[j].next = adjused ;
++adjused ;
}
memset( visited, false, sizeof( visited ) ) ;
if ( solve( 0, -1 ) != n )
printf( "NO\n" ) ;
else
printf( "YES\n" ) ;
}
return 0 ;
}