HDU-1811 Rank of Tetris 并查集+拓扑排序
该题的难点在于如何去处理掉等号,这里要用到并查集来处理相同的点,不要在输入的时候处理数据,一定要先将数据全部读取完再处理,这是因为相等的点的出现是不可预见的,很可能不能把相等的点的信息全部加到一个点的邻接表上去。
这里说明两条定理:
*如果一次入队入度为零的点大于1则说明拓扑排序序列不唯一
*如果排序的总个数小于给定的个数,则说明存在回路
这两种情况就对应了不同的错误,前者则是信息不完全,后者则是冲突。当然信息不完全不能够说明它不冲突。
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 10005
typedef struct E
{
int sign;
struct E *next;
} E;
struct
{
int dg;
struct E *next;
}v[MAX];
int x[MAX], y[MAX], set[MAX], N, M;
char op[MAX];
int queue[MAX], front, rear;
int find( int x )
{
return set[x]= x== set[x]? x: find( set[x] );
}
void merge( int x, int y )
{
int a= find( x ), b= find( y );
set[a]= b;
}
void insert( int x, int y )
{
E *e= ( E * )malloc( sizeof( E ) );
e-> sign= y;
e-> next= v[x]. next;
v[x]. next= e;
v[y]. dg++;
}
void swap( int &a, int &b )
{
int temp= a;
a= b;
b= temp;
}
void init( )
{
memset( v, 0, sizeof( v ) );
for( int i= 0; i< N; ++i )
{
set[i]= i;
}
front= rear= 0;
}
int main( )
{
while( scanf( "%d %d", &N, &M )!= EOF )
{
init( );
int un= 0, num= N;
for( int i= 0; i< M; ++i )
{
scanf( "%d %c %d", &x[i], &op[i], &y[i] );
if( op[i]== '=' )
{
if( find( x[i] )!= find( y[i] ) )
{
merge( x[i], y[i] );
num--;
}
}
}
for( int i= 0; i< M; ++i )
{
int a= find( x[i] ), b= find( y[i] );
if( op[i]== '=' )
{
continue;
}
if( op[i]== '<' )
{
swap( a, b );
}
insert( a, b );
}
for( int i= 0; i< N; ++i )
{
if( v[i].dg== 0&& find( i )== i )
{
queue[rear++]= i;
}
}
while( rear!= front )
{
if( rear- front> 1 )
{
un= 1;
}
int cur= queue[ front++ ];
num--;
for( E *p= v[cur]. next; p; p= p-> next )
{
if( --v[ p-> sign ]. dg== 0 )
{
queue[rear++]= p-> sign;
}
}
}
if( num> 0 )
{
puts( "CONFLICT" );
}
else if( un== 1 )
{
puts( "UNCERTAIN" );
}
else
{
puts( "OK" );
}
}
}