POJ 2723 Get Luffy Out(2-ST)

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

题意:给出 n 对钥匙,每对只能挑一把使用,每把只能用一次,也就是当一对钥匙中的一把被使用后,另一把也就不能再用了。给出 m 个门,每个门都有两把钥匙可以打开,问最多能开几道门(打开时必须按照顺序从前向后一个不落)。

思路:(1)n 对钥匙中,A 和 B 只能选择一把,用点 A 表示选择钥匙 A ,用 A’表示不选择,建边(A -> B‘)表示用钥匙 A 就不能用钥匙 B ;还有(B -> A' )表示用 B 就不能用 A;(2)m 道门,每对门都有两把钥匙可以开(假设是 C 和 D ),可能的选择是(不用 D 就必须用 C)或者(不用 C 就必须用D),根据这个关系建边(D' -> C),(C’-> D)。

 #include <stdio.h>

 #include <string.h>

 #include <stack>

 #define min(x,y) ((x)<(y)?(x):(y))

 using namespace std;

 

 struct node

 {

     int v,next;

 };

 

 

 

 const int MAX=5005;

 const int MAXE=13005;

 node edges[MAXE];

 int head[MAX],e;

 int dfn[MAX],low[MAX],visit[MAX],color[MAX],col[MAX];

 int n,m,index,cnt;

 stack<int> S;

 

 

 

 void Add(int u,int v)

 {

     edges[e].v=v;

     edges[e].next=head[u];

     head[u]=e++;

 }

 

 

 

 void Tarjan(int u)

 {

     int i,v;

 

     low[u]=dfn[u]=++index;S.push(u);visit[u]=1;

     for(i=head[u];i!=-1;i=edges[i].next)

     {

         v=edges[i].v;

         if(!dfn[v])

         {

             Tarjan(v);

             low[u]=min(low[u],low[v]);

         }

         else if(visit[v]) low[u]=min(low[u],dfn[v]);

     }

     if(dfn[u]==low[u])

     {

         cnt++;

         do

         {

             v=S.top();

             S.pop();

             visit[v]=0;

             color[v]=cnt;

         }while(u!=v);

     }

 }

 

 

 

 int TWO_ST()

 {

     int i;

 

     memset(dfn,0,sizeof(dfn));

     memset(visit,0,sizeof(visit));

     index=cnt=0;

     while(!S.empty()) S.pop();

     for(i=0;i<2*n;i++) if(!dfn[i]) Tarjan(i);

     for(i=0;i<n;i++) if(color[i*2]==color[i*2+1]) return 0;

     return 1;

 }

 

 int a[MAX][2],b[MAX][2];

 

 inline int OK(int K)

 {

     if(!K) return 1;

     

     return TWO_ST();

 }

 

 int main()

 {

     while(scanf("%d%d",&n,&m),n||m)

     {

         int i,ans;

         for(i=1;i<=n;i++) scanf("%d%d",&b[i][0],&b[i][1]);

         for(i=1;i<=m;i++) scanf("%d%d",&a[i][0],&a[i][1]);

         int low=0,high=m,mid;

         while(low<=high)

         {

             mid=(low+high)>>1;

             memset(head,-1,sizeof(head));

             e=0;

             for(i=1;i<=n;i++) 

             {

                 Add(2*b[i][0],2*b[i][1]+1);

                 Add(2*b[i][1],2*b[i][0]+1);

             }

             for(i=1;i<=mid;i++)

             {

                 Add(2*a[i][0]+1,2*a[i][1]);

                 Add(2*a[i][1]+1,2*a[i][0]);

             }

             if(OK(mid)) ans=mid,low=mid+1;

             else high=mid-1;

         }

         printf("%d\n",ans);

     }

     return 0;

 }

  

 

 

 

你可能感兴趣的:(get)