LOJ2723

LOJ2723 Get Luffy Out

题目大意:给你n对钥匙,每对钥匙只可以用其中的任意一个,钥匙有编号,且不重复。有m个大门,每个门上有两个锁,每个锁对应一个编号的钥匙,只要打开两个锁中的一个就可以打开门。问用这n对钥匙最多可以打开多少大门(门有顺序)?

——————————————————————————————————————————————

每一个大门要打开,要么用A钥匙,要么用B钥匙,这是明现的2-SAT问题。

同一对钥匙,用了A钥匙就一定不能用B钥匙。

对于最多可以打开多少门,因为门有顺序,所以要二分答案。

——————————————————————————————————————————————

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn=1050;
 7 const int maxm=2100;
 8 int n,m;
 9 int keys[maxn<<1],doors[maxm][2];
10 struct edge
11 {
12     int u,v,nxt;
13 }e[maxm<<1];
14 int head[maxn<<1],js;
15 void addage(int u,int v)
16 {
17     e[++js].u=u;e[js].v=v;
18     e[js].nxt=head[u];head[u]=js;
19 }
20 int low[maxm<<1],dfn[maxm<<1],cnt,st[maxm<<1],top,lt[maxm<<1],lts;
21 void tarjan(int u)
22 {
23     low[u]=dfn[u]=++cnt;
24     st[++top]=u;
25     for(int i=head[u];i;i=e[i].nxt)
26     {
27         int v=e[i].v;
28         if(!dfn[v])
29         {
30             tarjan(v);
31             low[u]=min(low[u],low[v]);
32         }
33         else if(!lt[v]) low[u]=min(low[u],dfn[v]);
34     }
35     if(low[u]==dfn[u])
36     {
37         lt[u]=++lts;
38         while(st[top]!=u)lt[st[top--]]=lts;
39         --top;
40     }
41 }
42 bool pd(int x)
43 {
44     memset(head,0,sizeof head);
45     js=0;
46     for(int a,b,i=0;i<x;++i)
47     {
48         a=doors[i][0],b=doors[i][1];
49         if(a==b)addage(keys[a]^1,keys[a]);
50         else
51         {
52             addage(keys[a]^1,keys[b]);
53             addage(keys[b]^1,keys[a]);
54         }
55     }
56     memset(low,0,sizeof low);
57     memset(dfn,0,sizeof dfn);
58     cnt=0;
59     memset(lt,0,sizeof lt);
60     lts=0;
61     top=0;
62     for(int i=2;i<n*2+2;++i)
63         if(!dfn[i])tarjan(i);
64     for(int i=1;i<n+1;++i)
65         if(lt[i<<1]==lt[(i<<1)^1])return 0;
66     return 1;
67 }
68 int main()
69 {
70     while(scanf("%d%d",&n,&m),n+m)
71     {
72         for(int a,b,i=1;i<=n;++i)
73         {
74             scanf("%d%d",&a,&b);
75             keys[a]=i<<1;
76             keys[b]=(i<<1)^1;
77         }
78         for(int i=0;i<m;++i)
79             scanf("%d%d",&doors[i][0],&doors[i][1]);
80         int l=0,r=m,ans=0;
81         while(l<=r)
82         {
83             int mid=(l+r)>>1;
84             if(pd(mid))ans=mid,l=mid+1;
85             else r=mid-1;
86         }
87         printf("%d\n",ans);
88     }
89     return 0;
90 }
View Code

 

转载于:https://www.cnblogs.com/gryzy/p/10929380.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值