在此提供了两种解法:(1)利用树的性质,除了根节点入度为0外,其余节点入度均为1;(2)利用并查集,但是并查集检测是否存在多余的边后,还要检测全部节点构成的是树还是森林。比如测试数据 1 2 2 3 4 5 0 0。
Solution 1:
#include <iostream>
#include <vector>
using namespace std;
const int MAXSIZE = 10024;
vector<int> degree;
vector<bool> flags;
int main()
{
int k = 0;
int u, v;
while( (cin >> u >> v) && (~u || ~v) )
{
degree.assign(MAXSIZE, 0);
flags.assign(MAXSIZE, false);
++k;
degree[v]++;
flags[u] = true;
flags[v] = true;
if( !u && !v )
{
cout << "Case " << k << " is a tree." << endl;
continue;
}
while( (cin >> u >> v) && (u || v) )
{
degree[v]++;
flags[u] = true;
flags[v] = true;
}
// Judge
int cnt0 = 0, cnt1 = 0;
int n = 0;
int i;
for(i = 0; i < MAXSIZE; ++i)
{
if( flags[i] )
{
++n;
if( degree[i] == 1 )
++cnt1;
else if( degree[i] == 0 )
++cnt0;
else break;
}
}
if(i == MAXSIZE && cnt0 == 1 && cnt1 == n-1)
cout << "Case " << k << " is a tree." << endl;
else cout << "Case " << k << " is not a tree." << endl;
}
return 0;
}
Solution 2:
#include <iostream>
#include <vector>
using namespace std;
const int MAXSIZE = 10024;
int k = 0;
vector<int> p, r;
vector<bool> vex;
void MakeSet()
{
p.clear();
p.resize( MAXSIZE );
r.assign(MAXSIZE, 0);
for(int i = 0; i < MAXSIZE; ++i)
p[i] = i;
}
int FindSet(int c)
{
if(p[c] != c)
p[c] = FindSet(p[c]);
return p[c];
}
void Union(int lc, int rc)
{
int lp = FindSet(lc);
int rp = FindSet(rc);
if( r[lp] < r[rp] )
p[lp] = rp;
else
{
p[rp] = lp;
r[lp]==r[rp]?r[lp]++:NULL;
}
}
int main()
{
int u, v;
while( (cin >> u >> v) && (~u || ~v) )
{
++k;
if( !u && !v )
{
cout << "Case " << k << " is a tree." << endl;
continue;
}
MakeSet();
vex.assign(MAXSIZE, false);
bool ans = true;
do
{
if( ans )
{
vex[u] = true;
vex[v] = true;
if(FindSet(u) != FindSet(v))
Union(u, v);
else
ans = false;
}
}while( (cin >> u >> v) && (u || v) );
if( ans )
{
int s = -1;
for(int i = 0; i < MAXSIZE; ++i)
if( vex[i] )
{
if( s == -1 )
s = FindSet( i );
else if( s != FindSet(i) )
{
ans = false;
break;
}
}
}
cout << "Case " << k << (ans?" is a tree.":" is not a tree.") << endl;
}
return 0;
}