• POJ


    题意:有2N个钥匙和M道门,每道门上有2个钥匙孔,只要打开一个即可。两个钥匙组成一个集合,共N个集合,集合中的一个钥匙被使用则另外一个钥匙会失效。求从前往后,最多能开几扇门。
    分析:从集合元素为2易推断出是2-SAT的问题,但本题求最大的解决数,所以考虑二分求解。
    一个集合中的钥匙a,b,若选a则必不选b;选b则必不选a。用2i和2i+1代表选第i个钥匙和不选第i个钥匙,加边a->b' , b->a'.
    对于每道门,因为只要一个钥匙孔满足即可,构成的关系是析取,加边a'->b, b'->a。
    二分能够开启的门数量,每次重新建图判断是否可行。

    #include<stdio.h>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<stack>
    using namespace std;
    typedef long long LL;
    const int maxn =5e3+5;
    const int maxm = 1e5+5;
    struct Edge{
        int v,next;  
    }edges[maxm<<1];
    int head[maxn],tot;
    stack<int> S;
    int pre[maxn],low[maxn],sccno[maxn],dfn,scc_cnt;
    void init()
    {
        tot = dfn = scc_cnt=0;
        memset(pre,0,sizeof(pre));
        memset(sccno,0,sizeof(sccno));
        memset(head,-1,sizeof(head));
        while(!S.empty()) S.pop();
    }
    void AddEdge(int u,int v)   {
        edges[tot] = (Edge){v,head[u]};
        head[u] = tot++;
    }
    
    void Tarjan(int u)
    {
        int v;
        pre[u]=low[u]=++dfn;
        S.push(u);
        for(int i=head[u];~i;i=edges[i].next){
            v= edges[i].v;
            if(!pre[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!sccno[v]){
                low[u]=min(low[u],pre[v]);
            }
        }
        if(pre[u]==low[u]){
            int x;
            ++scc_cnt;
            for(;;){
                x = S.top();S.pop();
                sccno[x]=scc_cnt;
                if(x==u)break;
            }
        }    
    }
    int N,M;
    int p1[maxn],p2[maxn];
    int key1[maxn],key2[maxn];
    bool check(int n)
    {
        init();
        for(int i=1;i<=N;++i){
            AddEdge(key1[i]*2,key2[i]*2+1);
            AddEdge(key2[i]*2,key1[i]*2+1);
        }
        for(int i =1;i<=n;++i){
            AddEdge(p1[i]*2+1,p2[i]*2);
            AddEdge(p2[i]*2+1,p1[i]*2);
        }   
        int all = 2*N;
        for(int i=0;i<all;++i){
            if(!pre[i]) Tarjan(i);
        }
        for(int i=0;i<N;i+=2){
            if(sccno[i]==sccno[i^1]) return false; 
        }
        return true;
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        while(scanf("%d %d",&N,&M)==2){
            if(!N &&!M) break;
            for(int i=1;i<=N;++i){
                scanf("%d %d",&key1[i],&key2[i]);
            }
            for(int i=1;i<=M;++i){
                scanf("%d %d",&p1[i],&p2[i]);
            }
            int L= 0,R=M,mid,ans = 0;
            while(L<=R){
                mid = (L+R)>>1;
                if(check(mid)){
                    L = mid+1;
                    ans = mid;
                }
                else R= mid-1;
            }
            printf("%d
    ",ans);
        }    
        return 0;
    }
    
    
    为了更好的明天
  • 相关阅读:
    糊涂的教授
    有趣的英语角
    聚会
    新年礼物
    三核苷酸
    数字编码
    【同行说技术】iOS程序员从小白到大神必读资料汇总
    【同行说技术】Android图片处理技术资料汇总(一)
    【同行说技术】swift最全学习资料汇集(一)
    【同行说技术】iOS程序员从小白到大神必读资料汇总(一)
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9553879.html
Copyright © 2020-2023  润新知