zoukankan      html  css  js  c++  java
  • poj 2723 二分+2-sat判定

    题意:给出n对钥匙,每对钥匙只能选其中一个,在给出每层门需要的两个钥匙,只要一个钥匙就能开门,问最多能到哪层。

    思路:了解了2-SAT判定的问题之后主要就是建图的问题了,这里建图就是对于2*n个钥匙,分别分成a和a'两组,即选了比如a,b一组钥匙,选择了a则必须选择b',那么进行连边,而对于每层门,若该门能开,且选择了a',则b肯定需要选,那么a'和b连边。最后就是判定了,同样的 若a与a'在同一个连通分量中,表示无解。这题需要利用二分枚举答案m。

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #define MAXN 5005
    #define MAXM 50005
    #define inf 100000000
    using namespace std;
    struct Edge
    {
        int v,next;
    }edge[MAXM];
    int n,m,tot;
    int top,scnt,index;
    int low[MAXN],dfn[MAXN],instack[MAXN],head[MAXN];
    int stack[MAXN],fa[MAXN],a[MAXN],b[MAXN],hash[MAXN];
    int x[MAXN],y[MAXN];
    void init()
    {
        top=scnt=index=tot=0;
        memset(head,-1,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(instack,0,sizeof(instack));
    }
    void addedge(int u,int v)
    {
        edge[tot].v=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    void tarjan(int u)
    {
        low[u]=dfn[u]=++index;
        instack[u]=1;
        stack[++top]=u;
        int v;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(instack[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u])
        {
            scnt++;
            do
            {
                v=stack[top--];
                instack[v]=0;
                fa[v]=scnt;
            }while(v!=u);
        }
    }
    bool check(int n)
    {
        for(int i=1;i<=n;i++)
        {
            if(fa[i]==fa[i+n]) return false;
        }
        return true;
    }
    void build(int bound)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            addedge(a[i],b[i]+2*n);
            addedge(b[i],a[i]+2*n);
        }
        for(int i=1;i<=bound;i++)
        {
            addedge(x[i]+2*n,y[i]);
            addedge(y[i]+2*n,x[i]);
        }
        for(int i=1;i<=2*n;i++)
        {
            if(!dfn[i])tarjan(i);
        }
    }
    void solve()
    {
        int ans=0;
        int low=0,high=m;
        while(low<=high)
        {
            int mid=(low+high)>>1;
            build(mid);
            if(check(2*n))ans=max(ans,mid),low=mid+1;
            else high=mid-1;
        }
        printf("%d
    ",ans);
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
    		if(n==0&&m==0)break;
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%d%d",&a[i],&b[i]);
    			a[i]++;b[i]++;
    		}
    		for(int i=1;i<=m;i++)
    		{
    			scanf("%d%d",&x[i],&y[i]);
    			x[i]++;y[i]++;
    		}
    		solve();
        }
        return 0;
    }
    


     

  • 相关阅读:
    博客作业03--栈和队列
    博客作业02---线性表
    博客作业01-抽象数据类型
    C语言最后一次作业--总结报告
    C语言博客作业--函数嵌套调用
    java课程设计——2048
    博客作业06--图
    博客作业05--查找
    博客作业04--树
    博客作业03--栈和队列
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134107.html
Copyright © 2011-2022 走看看