版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目连接 poj
题意
给一个无向图,
如果 连通 并且 无环 , 输出 Yes,
否则 No
题解
先贴一个玄学错误, 这份代码改下万能头在 hdu 上交 c++ 是 47ms 过了的, 交 g++ 是 wa
要想交 g++ 需要把判断连通的时候注释掉break
古怪的输入格式
先用并查集判环, 如果有环直接标记, 读完数据后输出 No, 这种情况表容易处理
如果标记是无环, 那么需要判断数据给出的图是否连通, 也就是判断并查集个数, 一个并查集那么这个图是连通的输出Yes, 否则 No
tips : 在读数据的同时需要 合并两个顶点, 还需要标记这两个点是数据给出的点( 点并不连续, 如样例图一缺少1号顶点 )
代码
#include <bits/stdc++.h>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
typedef long long ll;
class DisjointSet {
public:
static const int MAXN = 1e5 + 100;
int n;
int root[MAXN];
DisjointSet ( ) {};
DisjointSet ( int _n ) : n ( _n ) {};
void INI ( int n ) {
this->n = n;
for ( int i = 0; i <= n; ++i ) root[i] = i;
}
int GET ( int x ) {
return root[x] == x ? x : root[x] = GET ( root[x] );
}
bool MERGE ( int x, int y ) {
int rx = GET ( x ), ry = GET ( y );
if ( rx == ry ) return false;
root[ry] = rx; return true;
}
}ds;
bool isVertex[ds.MAXN];
int main ( ) { // freopen( "F:\\in\\.txt" , "r" , stdin );
int u, v;
while ( ~sc( "%d%d", &u, &v ) ) {
if ( u==-1 && v==-1 ) break;
ds.INI ( ds.MAXN );
memset ( isVertex, false, sizeof( isVertex ) );
bool hasLoop = false;
while ( 1 ) {
if ( u==0 && v==0 ) break;
isVertex[u] = true, isVertex[v] = true;
if ( !ds.MERGE( u, v ) ) // 没有融合成功那一定是根相同, 即有环
hasLoop = true;
sc( "%d%d", &u, &v );
}
if ( hasLoop==true )
pf ( "No\n" );
else {
int sum = 0; // 统计并查集个数, 以确定图是否连通
for ( int i = 0; i <= ds.MAXN; ++i )
if ( isVertex[i] && ds.root[i]==i ) {
sum++;
if ( sum>1 ) break; // 交 g++ 需要注释掉这一行, 玄学错误, 给爷整懵了 ...
}
pf( "%s\n", sum>1 ? "No" : "Yes" );
}
}
return 0;
}