• poj-2723(2-sat+二分)


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

    题意:有m层楼,每楼有一扇门,门上有两把锁,打开其中一把就可以打开门,门只能顺序打开

    现在有n对不同的钥匙(即2*n把钥匙),每对钥匙只能有一把,问最多打开几扇门

    解题思路:

    因为钥匙只能二选一,所以想到2-sat

    因为每个门的锁是限制的,我们对其钥匙建图,锁来限制。

    怎么建图呢?

    假如锁为 a,b,我们选a或者b是没有限制条件的都可以打开,如果选  a'必须选b所以建边(a',b) ,如果选b‘必须选a,所以建(b',a);

    当a,b相等时,即都是a,选a即可,不能选a',这个一定要表示出来,我们建(a',a),使选a'变成不能成立。因为连了边使选了a',一定要选a。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn=4100;
    int n,m;
    struct node{
        int u,v,next;
    }e[maxn];
    int key[maxn],h[maxn],low[maxn],dfn[maxn];
    int visit[maxn],st[maxn],belong[maxn];
    int cnt,tot,top,num,a[maxn],b[maxn];
    
    void init()
    {
        memset(h,-1,sizeof(h));
        memset(visit,0,sizeof(visit));
        memset(dfn,0,sizeof(dfn));
        memset(belong,0,sizeof(belong));
        cnt=num=top=tot=0;    
    }
    
    void add(int u,int v)//连边 
    {
        e[cnt].u=u;
        e[cnt].v=v;
        e[cnt].next=h[u];
        h[u]=cnt++;
    }
    
    void tarjan(int u)
    {
        low[u]=dfn[u]=++tot;
        visit[u]=1;
        st[++top]=u;
        for(int i=h[u];i!=-1;i=e[i].next)
        {
            int v=e[i].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            if(visit[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            int t;
            num++;
            do{
                t=st[top--];
                visit[t]=0;
                belong[t]=num;
            }while(t!=u);
        }
    }
    
    bool jug(int x)
    {
        init();//每次初始化 
        for(int i=0;i<x;i++)//建边 
        {
            if(a[i]==b[i])
                add(key[a[i]]^1,key[a[i]]);
            else
            {
                add(key[a[i]]^1,key[b[i]]);
                add(key[b[i]]^1,key[a[i]]);
            }
        }
        for(int i=0;i<2*n;i++)
            if(!dfn[i])
                tarjan(i);
        for(int i=0;i<n;i++)
            if(belong[2*i]==belong[2*i+1])//不成立 
                return false;
        return true;
    }
    
    int main()
    {
        std::ios::sync_with_stdio(false);
        int x,y;
        while(cin>>n>>m)
        {
            if(!n&&!m)
                break;
            for(int i=0;i<n;i++)
            {
                cin>>x>>y;
                key[x]=2*i;
                key[y]=2*i+1;
            }
            for(int i=0;i<m;i++)
                cin>>a[i]>>b[i];    
            int l=0,r=m,ans=0;
            while(l<=r)//二分答案 
            {
                int mid=(l+r)/2;
                if(jug(mid))
                {
                    ans=mid;
                    l=mid+1;
                }
                else
                    r=mid-1;
            }
            cout<<ans<<endl;
        }    
        return 0;
    }
  • 相关阅读:
    list转datatable c#
    按钮靠右css小结
    IE浏览器打印合格证相关问题
    vue项目插入视频-mp4
    vue项目bug-Couldn’t find preset "es2015"
    Mac打开swf文件
    mac+windows下从git上拉取项目及运行
    echarts.js制作中国地图
    前端数据可视化echarts.js
    vue-router 基本使用
  • 原文地址:https://www.cnblogs.com/xiongtao/p/10624040.html
Copyright © 2020-2023  润新知