zoukankan      html  css  js  c++  java
  • poj2723 2sat判断解+二分

    典型的2-sat问题,题意:有m个门,每个门上俩把锁,开启其中一把即可,现在给n对钥匙(所有

    钥匙编号0123456...2n-1),每对钥匙只能用一把,要求尽可能开门多(按顺序,前max个)。

    关键是题意的分析与转化,只能选一?必然2-sat,每给一对门上的锁对应钥匙的编号,说:必需要这

    俩把钥匙的一把(至少),即:a^b,所以,建图了可以,总结通法:对应的数据编号:0123..,每个
    数代表原来的一个“状态”/“命题”/“数据”,使之01为一对(只取一个),23一对,...依次,建图
    此题要求最值,二分即可。
    注意点(WA之因):1.编号后全图全按编号走啊!原来数据基本无用,只是有时候输出时之用,或建立
    数据双向关系!2.对于每次二分,对应数要重新建图,注意初始化!

    ps:一晚没成功,结果早上起来2分钟,AC!上午效率就是高!切记不可熬夜!身体健康第一位!

    #include<iostream>    //36MS
    #include<cstring>
    #include<cstdio>
    #include<stack>
    #include<vector>
    using namespace std;
    const int MAX=3000;
    vector<int>keys(MAX);int n,m;int times=0;
    int belong[MAX];
    int low[MAX];int dfn[MAX];int visited[MAX];int isinstack[MAX];stack<int>s;
    int scc[MAX];int numblock=0;
    struct request                  //条件
    {
        int a,b;
    };
    request requests[MAX];
    vector<vector<int> >edges(MAX);  //图
    void clear()
    {
        times=numblock=0;
        for(int i=0;i<2*n;i++)
        {
            visited[i]=dfn[i]=low[i]=isinstack[i];
            scc[i]=-1;
            edges[i].clear();
        }
    }
    void tarjan(int u)       //dfs
    {
        dfn[u]=low[u]=++times;
        isinstack[u]=1;
        s.push(u); int len=edges[u].size();
        for(int i=0;i<len;i++)
           {
               int v=edges[u][i];
               if(visited[v]==0)
               {
                   visited[v]=1;
                   tarjan(v);
                   if(low[u]>low[v])low[u]=low[v];
               }
               else if(isinstack[v]&&dfn[v]<low[u])
                  low[u]=dfn[v];
           }
        if(low[u]==dfn[u])
        {
            numblock++;int cur;
            do
            {
                cur=s.top();s.pop();
                isinstack[cur]=0;
                scc[cur]=numblock;
            }while(cur!=u);
        }
    }
    bool check(int maxnum)           //检查
    {
         clear();
        for(int i=0;i<maxnum;i++)     //这里的数据的转化
        {
            if(requests[i].a==requests[i].b)
               {
                   edges[belong[requests[i].a]^1].push_back(belong[requests[i].b]);
               }
          else
          {
           edges[belong[requests[i].a]^1].push_back(belong[requests[i].b]);
           edges[belong[requests[i].b]^1].push_back(belong[requests[i].a]);
          }
        }
        for(int i=0;i<2*n;i++)
             if(visited[i]==0)
             {
                 visited[i]=1;
                 tarjan(i);
             }
        for(int i=0;i<2*n;i+=2)
            if(scc[i]==scc[i+1])         //因为这里跪了半天!注意编号!图顶点用的都是编号!
                    return 0;
         return 1;
    }
    void readin()
    {
        for(int i=0;i<2*n;i++)
        {
            scanf("%d",&keys[i]);
            belong[keys[i]]=i;
        }
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&requests[i].a,&requests[i].b);
        }
    }
    int main()
    {
        while(~scanf("%d%d",&n,&m)&&(n||m))
        {
            readin();
            int left=0,right=m,mid;
            int count=-1;
            while(right>left)       //二分之
            {
                mid=(left+right)/2;
                if(mid==count&&mid==left)   //注意出口!
                {
                    if(check(left+1))left++;
                    break;
                }
                if(check(mid))
                    left=mid;
                else right=mid;
               count=mid;
             }
            printf("%d
    ",left);
        }
    }
    


  • 相关阅读:
    CentOS7.6下 MariaDB的MHA 集群搭建(一)
    Mariadb10.4 集群压力测试(一)
    Galera 核心参数详解(一)
    Mariadb10.4+ ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
    手动打造一个弹窗程序
    IAT HOOK
    进制的本质
    基于数组越界的缓冲区溢出
    函数调用堆栈图-c语言
    算法之二分查找(上)-c语言实现
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925811.html
Copyright © 2011-2022 走看看