【UVA1146】NOW OR LATER 2-SAT问题
2015-09-07 19:58
309 查看
题目大意:有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(非原创……)
输入格式:
输入包含若干组数据。每组数据第一行为飞机的数目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(非原创……)
[code]#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 2000 #define clr(a) memset(a,0,sizeof(a)) #define inf 0x7fffffff/2 using 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; }
相关文章推荐
- XAMPP+Mantis安装步骤
- 讲解actionbar 比较好的文章
- Codeforces 156D Clues (图论, 并查集, 卡特兰数)
- [国家集训队2012]tree(伍一鸣)
- Win10系统给绿色版msysGit添加Git Bash Here
- 2015.9.7 来到B公司的第三天
- 等效全向辐射功率(EIRP)
- skia DrawLooper
- Processing 练习(6)- 模拟电磁场 - 三角函数应用
- TCP标志位之RST
- FTP主动模式和被动模式的区别
- C++默认参数注意事项
- 最大公约数gcd实现
- 继承 初始化方法 遍历构造器
- oracle 各种常用函数讲解
- 沟通的囧途
- 网络编程
- Spinner下拉列表组件的3种数据绑定方式
- mysql中文进行全文索引支持问题
- ioS开发之网络--网络基础概况