• UVALive-3211 Now or later (2-SAT+二分)


    题目大意:有n架飞机,每架飞机有两个可选择的着陆时间,并且每架飞机都必须要选一个时间着陆。为了安全考虑,要求两架飞机的最小着陆时间差最大,找出这个最大值。

    题目分析:有“最小值的最大值”这样的字眼,用二分。二分枚举这个最小时间差的最大值p,则问题变成了这样的:有n个只有两个元素的集合,每个元素代表一个时间点,现在要从这些集合中选出n个(一个集合中必须选出一个)元素构成新的集合,使得新集合中任意两点之间的差值都不小于p,找到满足条件的最大的p。

      如果两个不同集合中的两个元素(一个集合中一个)之间的差值(绝对值,也就是时间差)小于p,那么这两个元素之间便有矛盾,不能同时被选。例如:设x1、x2为同一个集合中的元素,y1、y2为另一个集合中的元素,如果x1与y1之差小于p,那么如果选了x1就必须选y2,反过来,选了y1就必须选x2。这样就是2-SAT模型了。只需找出使得这个2-SAT有解的最大p即可。

    代码如下:

    # include<iostream>
    # include<cstdio>
    # include<vector>
    # include<cstring>
    # include<algorithm>
    using namespace std;
    
    const int maxn=2005;
    int n,cnt,S[maxn*2],mark[maxn*2],Table[maxn][2];
    vector<int>G[maxn*2];
    
    void add(int x,int a,int y,int b)
    {
        x=x*2+a;
        y=y*2+b;
        G[x^1].push_back(y);
        G[y^1].push_back(x);
    }
    
    bool dfs(int u)
    {
        if(mark[u^1])   return false;
        if(mark[u]) return true;
        mark[u]=1;
        S[cnt++]=u;
        for(int i=0;i<G[u].size();++i)
            if(!dfs(G[u][i]))
                return false;
        return true;
    }
    
    bool judge(int M)
    {
        for(int i=0;i<2*n;++i)  G[i].clear();
        memset(mark,0,sizeof(mark));
        for(int i=0;i<n;++i)
            for(int a=0;a<2;++a)
                for(int j=i+1;j<n;++j)
                    for(int b=0;b<2;++b)
                        if(abs(Table[i][a]-Table[j][b])<M)
                            add(i,a^1,j,b^1);
        for(int i=0;i<2*n;i+=2){
            if(!mark[i]&&!mark[i+1]){
                cnt=0;
                if(!dfs(i)){
                    while(cnt>0)  mark[S[--cnt]]=0;
                    if(!dfs(i+1))   return false;
                }
            }
        }
        return true;
    }
    
    int main()
    {
        int L,R;
        while(scanf("%d",&n)!=EOF)
        {
            L=R=0;
            for(int i=0;i<n;++i){
                scanf("%d%d",&Table[i][0],&Table[i][1]);
                R=max(R,max(Table[i][0],Table[i][1]));
            }
            while(L<R)
            {
                int M=L+(R-L+1)/2;
                if(judge(M)){
                    L=M;
                }else
                    R=M-1;
            }
            printf("%d
    ",L);
        }
        return 0;
    }
    

      

  • 相关阅读:
    GRUB引导——menu.lst的写法
    条形码类型及常见条形码介绍
    Tmux:终端复用器
    find+*的问题
    find命令之exec
    Linux core 文件介绍
    C语言中返回字符串函数的四种实现方法
    C语言中的volatile
    Stars
    Game with Pearls
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/4902598.html
Copyright © 2020-2023  润新知