poj 2723 Get Luffy Out

来源:互联网 发布:淘宝订单无法评价 编辑:程序博客网 时间:2024/04/29 11:58

题意:有 m 层楼,从一层到 m 层,要进入每层都要打开位于该层的两道门中的至少一道。门锁有 2n 种,每个门锁为 2n 种中的一种,可以重复。有 2n 把钥匙,分别对应 2n 种锁,但钥匙两两一组,共 n 组,每组只能选一个来开门,被选中的可重复使用,另一个不能用。问最多能上多少层。

分析:二分查找能上的层数。每次对于一个确定的层数,也就确定了哪些门需要开。变为一个2-sat问题。其中两两一组的钥匙就是图中的节点。当然图中还需要一些矛盾。矛盾如下,各组的两个钥匙相矛盾(这里无需建边);每层开门钥匙的选择关系里,(first_key && second_key = 0 )

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;const int maxn = 11000;const int inf = 1000000000;vector<int>edge[maxn];int n, m, match[maxn], s[maxn], e[maxn];int tmpdfn, dfn[maxn], low[maxn], inst[maxn], belong[maxn], st[maxn], top, scnt;void tarjan( int u ){int i, v, t, size;low[u] = dfn[u] = tmpdfn++;st[top++] = u;inst[u] = 1;size = edge[u].size();for( i = 0; i < size; i++ ){v = edge[u][i];if( dfn[v] == -1 ){tarjan( v );low[u] = min( low[u], low[v] );}else if( inst[v] )low[u] = min( low[u], dfn[v] );}if( dfn[u] == low[u] ){do{ belong[t = st[--top]] = scnt; inst[t] = 0; }while( t != u );scnt++;}}bool SCC(){int i;top = 0;tmpdfn = scnt = 1;memset( dfn, -1, sizeof(dfn) );memset( inst, 0, sizeof(inst) );for( i = 1; i <= n * 2; i++ )if( dfn[i] == -1 )tarjan( i );for( i = 1; i <= n; i++ )if( belong[i] == belong[match[i]] )return false;return true;}void build( int f ){int i, j;for( i = 1; i <= n * 2; i++ )edge[i].clear();for( i = 1; i <= f; i++ ){// it can choose one key each pair but none edge[s[i]].push_back( match[e[i]] );edge[e[i]].push_back( match[s[i]] );}}int main(){int i, a, b;while( ~scanf( "%d%d", &n, &m ), n + m ){for( i = 1; i <= n; i++ ){scanf( "%d%d", &a, &b );a++;b++;match[a] = b; match[b] = a;}for( i = 1; i <= m; i++ ){scanf( "%d%d", &s[i], &e[i] );s[i]++;e[i]++;}int l, r, mid;// 二分查找l = 0;r = m + 1;// 1 and m are boundary.while( l + 1 != r ){mid = l + ( r - l ) / 2;build( mid );if( SCC() )l = mid;elser = mid;}printf( "%d\n", l );}return 0;}


原创粉丝点击