首先明确连通具有对称性和传递性,然后对于给出的新的连通关系,判断该关系是否已经存在,是的话不用输出,否则输出这个新的连通关系。
总的来说,时间比较充裕(好吧,我承认我超时了几次……),关键在于更新状态。我最开始使用的是直接模拟的办法,用set来存放各个互不相交的集合,当新的连通关系出现时就合并这两个集合,结果华丽丽地超时了。修改时,发现时间主要消耗在set的insert函数(其有序性在这道题中是多余的),和查找某个数在哪个set里面(O(n)的时间复杂度)。于是乎,我就把set改为queue(其push函数插入队尾相当高效),并将用于记录数据是否存在的bool数组(保证唯一性)改为int数组,增加了记录某个数位于那个queue中的信息(这样查找就是O(1)的时间复杂度了)。经过这两个修改,就可以AC了。
另:输入的数在0-100000以内,包括100000,所以数组的大小要开到100001个,否则会RE。对于queue的数组要开多少,理论上来讲最多会有50000个,即2个数一个集合。虽然照这个开不会MLE,但也挺大的,而且挺耗时间。后来经过测试,开10001个就足够了。
Run Time: 1.38sec
Run Memory: 8884KB
Code length: 1275Bytes
SubmitTime: 2011-12-20 00:03:42
// Problem#: 4335
// Submission#: 1096428
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int main()
{
int a, b;
int t, k1, k2;
queue<int> q[ 10001 ];
int exist[ 100001 ];
memset( exist, -1, sizeof( exist ) );
while ( scanf( "%d%d", &a, &b ) != EOF ) {
if ( exist[ a ] == -1 && exist[ b ] == -1 ) {
t = 0;
while ( !q[ t ].empty() )
t++;
q[ t ].push( a );
q[ t ].push( b );
exist[ a ] = t;
exist[ b ] = t;
printf( "%d %d\n", a, b );
}
else if ( exist[ a ] != -1 && exist[ b ] != -1 ) {
if ( exist[ a ] == exist[ b ] )
continue;
t = exist[ b ];
while ( !q[ t ].empty() ) {
q[ exist[ a ] ].push( q[ t ].front() );
exist[ q[ t ].front() ] = exist[ a ];
q[ t ].pop();
};
printf( "%d %d\n", a, b );
}
else {
k1 = ( exist[ a ] != -1 ? a: b );
k2 = ( exist[ b ] != -1 ? a: b );
q[ exist[ k1 ] ].push( k2 );
exist[ k2 ] = exist[ k1 ];
printf( "%d %d\n", a, b );
}
}
return 0;
}