题目链接:http://poj.org/problem?id=2723

 

【题目大意】

有2n把钥匙,分成2组,给你每组的钥匙信息,并且每组的钥匙只能用一个。

有m个门,每个门有2个锁,只要打开一个锁这个门就开了。(顺序遇见m个门)

问你最多能够打开多少个门。

【解题思路】

因为只能门只能按照顺序打开,所以很自然二分是个很好的选择。
建图的依据:
1、每对钥匙a,b有(a->!b),(b->!a)   也就是 a and b = 0 a被用b不被用,或b被用a不被用,或a,b都不被用
2、每善门对应锁的钥匙a,b有(!a->b),(!b->a) 也就是 a or b = 1,用a能打开用b不能打开,或用b能打开用a不能打开,或用a能打开用b也能打开

用二分法求解:

 

我下面用了两种方法求解的,时间都差不多。也就是求解强连通分量的两种方法。

/*
POJ 2723 Get Luffy Out
AC代码
*/

#include
<stdio.h>
#include
<math.h>
#include
<iostream>
using namespace std;
const int MAXN=1<<12;
const int MAXM=1<<24;
struct Node
{
int l,r;
}e[MAXN];
struct Node1
{
int from,to,next;
}edge1[MAXM],edge2[MAXM];
int visit1[MAXN],visit2[MAXN],head1[MAXN],head2[MAXN],Belong[MAXN],T[MAXN];
int tol1,tol2,Bcnt,Tcnt;
int hash[MAXN];
void add(int a,int b)
{
edge1[tol1].from
=a;edge1[tol1].to=b;edge1[tol1].next=head1[a];head1[a]=tol1++;
edge2[tol2].from
=b;edge2[tol2].to=a;edge2[tol2].next=head2[b];head2[b]=tol2++;
}
void dfs1(int x)
{
int j;
visit1[x]
=1;
for(j=head1[x];j!=-1;j=edge1[j].next)
if(visit1[edge1[j].to]==0) dfs1(edge1[j].to);
T[Tcnt
++]=x;
}
void dfs2(int x)
{
int j;
visit2[x]
=1;
Belong[x]
=Bcnt;
for(j=head2[x];j!=-1;j=edge2[j].next)
if(visit2[edge2[j].to]==0) dfs2(edge2[j].to);
}
int main()
{
int i,j,n,m;
int right,left,mid,ans;
while(scanf("%d%d",&n,&m)!=EOF)
{

if(n==0&&m==0)break;
int a,b;
for(i=0;i<n;i++)
{
scanf(
"%d%d",&a,&b);
hash[a]
=b;
hash[b]
=a;
}
for(i=0;i<m;i++)
scanf(
"%d%d",&e[i].l,&e[i].r);
left
=0;
right
=m;
while(left<=right)
{
mid
=(left+right)/2;
for(i=0;i<4*n;i++)
{
head1[i]
=-1;
head2[i]
=-1;
visit1[i]
=0;
visit2[i]
=0;
}
tol1
=tol2=0;
Tcnt
=Bcnt=0;
for(i=0;i<2*n;i++)
{
add(i,hash[i]
+2*n);
}
for(i=0;i<mid;i++)
{

if(e[i].l!=e[i].r)
{
add(e[i].l
+2*n,e[i].r);
add(e[i].r
+2*n,e[i].l);
}
if(e[i].l==e[i].r)
{
add(e[i].l
+2*n,e[i].l);
}

}
for(i=0;i<4*n;i++)
if(!visit1[i]) dfs1(i);
for(i=Tcnt-1;i>=0;i--)
{
if(!visit2[T[i]])
{
dfs2(T[i]);
Bcnt
++;
}
}
for(i=0;i<2*n;i++)
{
if(Belong[i]==Belong[i+2*n]) break;
}
if(i>=2*n)
{
ans
=mid;left=mid+1;
}
else right=mid-1;
}
printf(
"%d\n",ans);
}
return 0;
}

 

 

/*
POJ 2723 Get Luffy Out
AC代码
*/
#include
<stdio.h>
#include
<math.h>
#include
<iostream>
using namespace std;
const int MAXN=1<<12;
const int MAXM=1<<24;
int n,m;
struct Node
{
int l,r;
}e[MAXN];
struct Node1
{
int from,to,next;
}edge[MAXM];
int ecnt;
int head[MAXN],Belong[MAXN],Stack[MAXN];
int top,idx,b_cnt;
int hash[MAXN];
int DFN[MAXN],LOW[MAXN];
bool Instack[MAXN];
void add(int a,int b)
{
edge[ecnt].from
=a;edge[ecnt].to=b;edge[ecnt].next=head[a];head[a]=ecnt++;

}
void Tarjan(int u)
{
int i,v;
DFN[u]
=LOW[u]=(++idx);
Stack[
++top]=u;
Instack[u]
=true;
for(i=head[u];i!=-1;i=edge[i].next)
{
v
=edge[i].to;
if(!DFN[v])
{
Tarjan(v);
if(LOW[u]>LOW[v])LOW[u]=LOW[v];
}
else if(Instack[v]&&LOW[u]>DFN[v])
LOW[u]
=DFN[v];
}
if(LOW[u]==DFN[u])
{
b_cnt
++;
do
{
v
=Stack[top--];
Instack[v]
=false;
Belong[v]
=b_cnt;
}
while(u!=v);
}

}
int solve()
{
int i;
b_cnt
=idx=top=0;
for(i=0;i<4*n;i++)
{
DFN[i]
=LOW[i]=0;
Belong[i]
=0;
Instack[i]
=false;
}
for(i=0;i<4*n;i++)
if(!DFN[i]) Tarjan(i);
for(i=0;i<2*n;i++)
{
if(Belong[i]==Belong[i+2*n])
return 0;
}
return 1;
}
int main()
{
int i,j;
int right,left,mid,ans;
while(scanf("%d%d",&n,&m)!=EOF)
{

if(n==0&&m==0)break;
int a,b;
for(i=0;i<n;i++)
{
scanf(
"%d%d",&a,&b);
hash[a]
=b;
hash[b]
=a;
}
for(i=0;i<m;i++)
scanf(
"%d%d",&e[i].l,&e[i].r);
left
=0;
right
=m;
while(left<=right)
{
mid
=(left+right)/2;
for(i=0;i<4*n;i++)
{
head[i]
=-1;
}
ecnt
=0;
for(i=0;i<2*n;i++)
{
add(i,hash[i]
+2*n);
}
for(i=0;i<mid;i++)
{

if(e[i].l!=e[i].r)
{
add(e[i].l
+2*n,e[i].r);
add(e[i].r
+2*n,e[i].l);
}
if(e[i].l==e[i].r)
{
add(e[i].l
+2*n,e[i].l);
}

}

if(solve())
{
ans
=mid;left=mid+1;
}
else right=mid-1;
}
printf(
"%d\n",ans);
}
return 0;
}

文章来源:http://www.cnblogs.com/kuangbin/archive/2011/08/24/2152038.html