// 题目来源:POJ 3678
// 题目大意:有很多点可取值0或1,它们之间有很多边为0或1,规定每条边由端点(xor,and,or)得到,求是否可行
// 解决方法:每个点的取值只有两种情况,非常符合2-sat,用强连通分量判断即可
// 特别注意:可通过在拆成的点对中搭边来保证最后的结果落在某个点上
#include <cstdio>
#include <string>
#define o 1002
#define _ 1000002
void link( int, int );
void tarjan( int );
int next[ _*4 ], g[ _*4 ], h[ o*4 ], code[ o*4 ], dfn[ o*4 ], low[ o*4 ], stack[ o*4 ];
int n, m, index, cnt, t, top;
bool ins[ o*4 ];
int main( )
{
freopen( "3678.in", "r", stdin );
freopen( "3678.out", "w", stdout );
scanf( "%d%d", &n, &m );
int aa, bb, cc;
char st[ 10 ];
for( int i = 1; i <= m; i++ )
{
scanf( "%d%d%d%s", &aa, &bb, &cc, st );
if( strcmp( st, "AND" ) == 0 )
if( cc == 0 )
{
link( aa+n, bb );
link( bb+n, aa );
}
else
{
link( aa+n, bb+n );
link( bb+n, aa+n );
link( aa, aa+n );
link( bb, bb+n );
}
if( strcmp( st, "OR" ) == 0 )
if( cc == 0 )
{
link( aa, bb );
link( bb, aa );
link( aa+n, aa );
link( bb+n, bb );
}
else
{
link( aa, bb+n );
link( bb, aa+n );
}
if( strcmp( st, "XOR" ) == 0 )
if( cc == 0 )
{
link( aa, bb );
link( bb, aa );
link( aa+n, bb+n );
link( bb+n, aa+n );
}
else
{
link( aa, bb+n );
link( bb, aa+n );
link( aa+n, bb );
link( bb+n, aa );
}
}
for( int i = 0; i < 2*n; i++ )
if( !dfn[ i ] ) tarjan( i );
for( int i = 0; i < n; i++ )
if( code[ i ] == code[ i + n ] )
{
printf( "NO" );
return 0;
}
printf( "YES" );
return 0;
}
void link( int aa, int bb )
{
next[ ++t ] = h[ aa ];
h[ aa ] = t;
g[ t ] = bb;
}
void tarjan( int i )
{
int j;
dfn[ i ] = low[ i ] = ++index;
stack[ ++top ] = i;
ins[ i ] = 1;
for( int k = h[ i ]; k; k = next[ k ] )
{
j = g[ k ];
if( !dfn[ j ] )
{
tarjan( j );
if( low[ j ] < low[ i ] ) low[ i ] = low[ j ];
}
else if( ins[ j ] && dfn[ j ] < low[ i ] )
low[ i ] = dfn[ j ];
}
if( dfn[ i ] == low[ i ] )
{
cnt++;
do
{
j = stack[ top-- ];
code[ j ] = cnt;
ins[ j ] = 0;
}
while( i != j );
}
}
【代码】POJ 3678
最新推荐文章于 2019-06-14 18:11:04 发布