// 题目来源:POJ 2723
// 题目大意:m道门,每道门两把锁,有n对钥匙,对应2*n把锁,已知一对钥匙内取出一把另一把就会消失,求按顺序最多可开多少门
// 解决方法:依然2-sat啦,只不过要带上二分答案
#include <cstdio>
#include <string>
#define o 10002
#define _ 10002
void link( int, int );
bool check( int );
void tarjan( int );
int next[_], g[_];
int h[o], stack[o], opp[o], a[o], b[o], dfn[o], low[o], code[o];
int n, m, t, index, top, cnt;
bool ins[o];
int main( )
{
freopen( "2723.in", "r", stdin );
freopen( "2723.out", "w", stdout );
scanf( "%d%d", &n, &m );
int aa, bb;
while( n != 0 )
{
memset( opp, 0, sizeof( opp ) );
for( int i = 1; i <= n; i++ )
{
scanf( "%d%d", &aa, &bb );
opp[aa] = bb;
opp[bb] = aa;
}
for( int i = 1; i <= m; i++ )
scanf( "%d%d", &a[i], &b[i] );
int left = 0, right = m, mid = ( left + right ) / 2 + 1;
while( right != left )
{
if( check( mid ) )
left = mid;
else
right = mid - 1;
mid = ( left + right ) / 2 + 1;
}
printf( "%d\n", left );
scanf( "%d%d", &n, &m );
}
return 0;
}
void link( int aa, int bb )
{
next[++t] = h[aa];
h[aa] = t;
g[t] = bb;
}
bool check( int m )
{
if( m == 0 ) return 1;
memset( next, 0, sizeof( next ) );
memset( h, 0, sizeof( h ) );
memset( dfn, 0, sizeof( dfn ) );
memset( low, 0, sizeof( low ) );
memset( code, 0, sizeof( code ) );
t = index = 0;
for( int i = 1; i <= m; i++ )
{
link( opp[ a[i] ], b[i] );
link( opp[ b[i] ], a[i] );
}
for( int i = 0; i < 2*n; i++ )
if( !dfn[i] ) tarjan( i );
for( int i = 0; i < 2*n; i++ )
if( code[i] == code[ opp[i] ] ) return 0;
return 1;
}
void tarjan( int i )
{
int j;
dfn[i] = low[i] = ++index;
stack[++top] = i;
ins[i] = true;
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] = false;
}
while( i != j );
}
}
【代码】POJ 2723
猜你喜欢
转载自blog.csdn.net/JarjingX/article/details/8518501
今日推荐
周排行