zoukankan      html  css  js  c++  java
  • POJ2723 Get Luffy Out解题报告tarjan+2-SAT+二分

    今天看到讲2-SAT比较好的blog,感觉微微的理解了2-SAT

    传送门

    参考: https://blog.csdn.net/leolin_/article/details/6680144

    题意:你有2*n把钥匙,但是在每一对钥匙中,用了a,就不能用b。你要用这么多钥匙去开尽可能多的门。开门的规则是:每个门对于两把钥匙,用一把去开就ok。

    注意2的10次方一点都不大~~1000。

    思路:注意开门是有顺序的,所以可以二分答案,每次用mid值规定的门数去建一个图,跑一边tarjan缩点,再check一下i和i+2*n,若是同一个缩点块中,则false(2-sat思想);

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <map>
    #include <set>
    #include <queue>
    #include <stack>
    #include <list>
    #include <iterator>
    
    using namespace std;
    
    #define pb push_back
    
    const int maxn = 5000+9;
    int n,m;
    int key[maxn][2],locks[maxn][2];
    int low[maxn],dfn[maxn],vis[maxn],belong[maxn],scc,tot;
    stack<int>s;
    vector<int>mp[maxn];
    
    void tarjan(int x)
    {
        dfn[x] = low[x] = ++tot;
        s.push(x);vis[x] = 1;
        for(int i=0; i<mp[x].size(); i++)
        {
            int v = mp[x][i];
            if(dfn[v]==0)
            {
                tarjan(v);
                low[x] = min(low[x],low[v]);
            }
            else if(vis[v])
            {
                low[x] = min(low[x],dfn[v]);
            }
        }   
        if(low[x]==dfn[x])
        {
            scc++;
            while(1)
            {
                int tmp = s.top();
                s.pop();
                vis[tmp] = 0;
                belong[tmp] = scc;
                if(tmp==x)break;
            }
        }
    }
    void init()
    {
        for(int i=1; i<=4*n; i++)mp[i].clear();
    }
    void build(int x)
    {
        init();
        for(int i=1; i<=n; i++)                 //因为mp不得不清空.所以连这个也要重新建
        {                                       
            int a = key[i][0],b = key[i][1];
            mp[a].pb(b+2*n);                       
            mp[b].pb(a+2*n);
        }
        for(int i=1; i<=x; i++)
        {
            int a = locks[i][0],b = locks[i][1];
    
            mp[a+2*n].pb(b);                    //对于开门来说,不用这把,就要用另一把钥匙;
            if(a!=b)mp[b+2*n].pb(a);
        }
    }
    
    void ini(){
        while(!s.empty())s.pop();
        scc = tot = 0;
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        memset(vis,0,sizeof(vis));
        memset(belong,0,sizeof(belong));
    }
    bool check(){
        ini();
        for(int i=1; i<=4*n; i++)
        {
            if(dfn[i]==0)tarjan(i);
        }
        for(int i=1; i<=2*n; i++)
            if(belong[i]==belong[i+2*n])
                return false;
        return true;
    }
    int main(){
        while(~scanf("%d%d", &n, &m)&&n+m)
        {
            for(int i=1; i<=n; i++)
            {
                scanf("%d%d",&key[i][0],&key[i][1]);
                key[i][0]++,key[i][1]++;
            }
            for(int i=1; i<=m; i++)
            {
                scanf("%d%d", &locks[i][0], &locks[i][1]);
                locks[i][0]++,locks[i][1]++;
            }
          
            int le = 1,ri = m;              //二分范围不要乱写!
            int ans;
            while(le<=ri)
            {
                int mid = (le + ri)>>1;
                build(mid);
                if(check())
                {
                    ans = mid;
                    le = mid + 1;
                }
                else ri = mid - 1;
            }
            printf("%d
    ",ans);
        }  
        return 0;
    }
    View Code
  • 相关阅读:
    Python中*和**的区别
    Python中str、list、numpy分片操作
    Python中bisect的使用方法
    Python中__str__和__repr__的区别
    Python中函数参数类型和参数绑定
    C++中explicit
    C++中const
    自动识别 URL
    .net中activex的替代技术:winform control(一)
    vs2005包加载有误的解决方法
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/9069140.html
Copyright © 2011-2022 走看看