zoukankan      html  css  js  c++  java
  • POJ 2723 Get Luffy Out(2-SAT)

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

    【题目大意】

      给出一些钥匙和M扇有顺序的门,每扇门可以用两种钥匙打开,
      每两把钥匙被绑在一起,绑在一起的钥匙只有其中一把可以使用,
      问最多能按顺序打开几扇门。

    【题解】

      因为门是按顺序的,因此能打开的门是单调,
      首先我们二分这个答案,判定是否可行,
      将二分得到的答案之前的门按两个钥匙孔拆分成两个点,
      两个绑在一起的钥匙属于对立面,而门的两个钥匙孔是OR关系
      A与B之间的OR关系,我们可以将其拆分为!A->B AND !B->A,
      m个关系联立,就可以用2-SAT验证是否可行,

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cstring> 
    using namespace std;
    const int MAX_V=10000;
    int V; //顶点数
    vector<int> G[MAX_V]; //图的邻接表表示
    vector<int> rG[MAX_V]; //反向图
    vector<int> vs; //后序遍历
    bool used[MAX_V];
    int cmp[MAX_V]; //所属强连通分量的拓扑序
    void add_edge(int from,int to){
        G[from].push_back(to);
        rG[to].push_back(from);
    } 
    void dfs(int v){
        used[v]=1;
        for(int i=0;i<G[v].size();i++){
            if(!used[G[v][i]])dfs(G[v][i]);
        }vs.push_back(v);
    }
    void rdfs(int v,int k){
        used[v]=1;
        cmp[v]=k;
        for(int i=0;i<rG[v].size();i++){
            if(!used[rG[v][i]])rdfs(rG[v][i],k);
        }
    }
    const int MAX_N=1<<10;
    const int MAX_M=1<<11;
    int N,M,x,y;
    int door[MAX_M][2],key[MAX_N];
    int scc(){
        memset(used,0,sizeof(used));
        vs.clear();
        for(int v=0;v<V;v++){if(!used[v])dfs(v);}
        memset(used,0,sizeof(used));
        int k=0;
        for(int i=vs.size()-1;i>=0;i--){
            if(!used[vs[i]])rdfs(vs[i],k++);
        }return k;
    }
    bool check(int x){
        V=2*N;
        for(int i=0;i<V;i++){G[i].clear();rG[i].clear();}
        for(int i=0;i<x;i++){
            add_edge(key[door[i][0]],door[i][1]);
            add_edge(key[door[i][1]],door[i][0]);
        }scc();
        for(int i=0;i<V;i++){
            if(cmp[i]==cmp[key[i]])return 0;
        }return 1;
    }
    int solve(){
        int l=0,r=M,ans=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(check(mid))l=mid+1,ans=mid;
            else r=mid-1;
        }return ans;
    }
    int main(){
        while(~scanf("%d%d",&N,&M),N+M){
            for(int i=0;i<N;i++){
                scanf("%d%d",&x,&y);
                key[x]=y; key[y]=x; 
            }for(int i=0;i<M;i++)scanf("%d%d",door[i],door[i]+1);
            printf("%d
    ",solve());
        }return 0;
    }
  • 相关阅读:
    my first blog
    iFrame 父子窗口通讯
    关于手机端横屏竖屏问题
    IE环境规定div高度必须大于字体高度的问题
    adMob的旋转方法
    影响一个UIView是否能正常显示的几个因素
    iphone编译时的注意事项
    Cocos2d的字体生成软件Hiero v2.0 Bitmap Font Tool的一些问题
    编写Web前端代码的注意事项
    Cocos2d的SpriteSheet在多层图片时出现的问题
  • 原文地址:https://www.cnblogs.com/forever97/p/poj2723.html
Copyright © 2011-2022 走看看