【UVA1146】NOW OR LATER 2-SAT问题

来源:互联网 发布:ios上玩的编程游戏 编辑:程序博客网 时间:2024/05/22 16:56

题目大意:有n架飞机需要着陆。每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种。第i架飞机的早着陆时间为Ei,晚着陆时间为Li,不得在其他时间着陆。你的任务是为这些飞机安排着陆方式,使得整个着陆计划尽量安全。换句话说,如果把所有飞机的实际着陆时间安照从早到晚的顺序排列,相邻两个着陆时间间隔的最小值(称为安全间隔)应尽量的大。
输入格式:
输入包含若干组数据。每组数据第一行为飞机的数目n(2<=n<=2 000)。以下n行每行两个整数,即早着陆时间和晚着陆时间。所有时间t满足0<=t<=107。输入结束标志为文件结束符(EOF)。
输出格式
对于每组数据,输出安全间隔的最大值。
思路:刚开始看到这题时博主有同学断言他是NPC的= =
将飞机i拆为2*i和2*i+1表示早着陆和晚着陆(我们把2*i和2*i+1称为对称点,则点x与x^1互为对称点,x对称点简称为x’)。二分答案t,若点i,j的时间差小于t,则建边i→j’,j→i’,意思是选点i必选j的对称点,选点j必选i的对称点。求出所有强连通分量后,若对于任意的i,都有i与i’所在强连通分量不同,那么当前答案下一定有解,否则无解。
关于2-SAT可参考博主某处PPT(非原创……)

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define maxn 2000#define clr(a) memset(a,0,sizeof(a))#define inf 0x7fffffff/2using namespace std;int t[2*maxn+10],n;struct EDGE{    int u,v,next;}edge[maxn*maxn*4+10];int head[2*maxn+10],pp;void addedge(int u,int v){    edge[++pp]=(EDGE){u,v,head[u]};    head[u]=pp;}void build(int u,int lim){    for(int i=0;i<2*n;i++)if(u/2!=i/2){        if(abs(t[i]-t[u])<lim){            addedge(u,i^1);        }       }}int dfn[maxn*2+10],low[maxn*2+10],clo;int sta[maxn*2+10],p;int sccno[maxn*2+10],scnt;void dfs(int u){    dfn[u]=low[u]=++clo;    sta[++p]=u;    for(int i=head[u];i;i=edge[i].next){        int v=edge[i].v;        if(!dfn[v]){            dfs(v);            low[u]=min(low[u],low[v]);        }else if(!sccno[v]){            low[u]=min(low[u],dfn[v]);        }    }    if(low[u]==dfn[u]){        scnt++;        for(;;){            int x=sta[p--];            sccno[x]=scnt;            if(x==u)break;        }    }}void findscc(int n){    clr(sccno);    clr(dfn);    clo=scnt=0;    for(int i=0;i<2*n;i++)if(!dfn[i])dfs(i);}bool judge(int x){    pp=0;    clr(head);    for(int i=0;i<2*n;i++){        build(i,x);    }    findscc(n);    for(int i=0;i<n;i++)if(sccno[2*i]==sccno[2*i+1])return 0;    return 1;   }int main(){    freopen("1146.in","r",stdin);    while(scanf("%d",&n)==1){        int r=0;        for(int i=0;i<2*n;i++){            scanf("%d",&t[i]);            r=max(r,t[i]);        }        int l=0,ans=0;        while(l<=r){            int m=(l+r)/2;            if(judge(m)){                ans=m;                l=m+1;            }else r=m-1;        }        printf("%d\n",ans);    }    return 0;} 
0 0
原创粉丝点击