HDU1811 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" );
}
}
}
原文地址:https://www.cnblogs.com/Lyush/p/2109174.html