---恢复内容开始---

题意:

  N个人想回家在至少一个时刻、至多两个时刻。并且,他们每个人都能独自回家。

  定义:ai表示第i个人回家的时间, xij = abs(ai - aj) (i != j).

  在每种时间计划中,定义 y = min{xij}。

  问y最大可能是多少?

解法:

  二分时间差的下界,用2-SAT判断是否可行。下确界即为所求。

代码:

这种是直接在跑的时候建边,是效率最快的  

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; const int MAXN = ;
const int INF = (int)1e9+; int a[MAXN];
bool mark[MAXN];
int S[MAXN], c;
int n; inline int myAbs(int x) {
return x> ? x : -x;
} void init() {
memset(mark, false, sizeof(mark));
memset(S, , sizeof(S));
c = ;
} bool dfs(int u, int k) {
if (mark[u^]) return false; //如果他的对立面和他同时被标记,那么这种情况不应该发生
if (mark[u]) return true; //如果他已经被标记 mark[u] = true; //他被标记
S[c++] = u; //这个点入栈
for (int i = ; i < n*; i++) if (u!=i && (u^)!=i) {
if (myAbs(a[u^]-a[i])<k) {
if (!dfs(i, k)) return false;
}
}
return true;
} bool check(int k) {
init();
for (int i = ; i < n*; i += ) {
if (!mark[i] && !mark[i|]) { //如果这个点没有被标记
c = ;
if (!dfs(i, k)) { //如果x不能赋值为真
while (c>) mark[S[--c]] = false;
if (!dfs(i|, k)) return false; //如果x也不能赋值为假,那么无解
}
}
}
return true;
} void slove() {
int l = , r = INF, m;
while (l<r) {
m = (l+r)>>;
if (!check(m)) r = m;
else l = m+;
}
printf("%d\n", r-);
} int main() {
#ifdef Phantom01
freopen("WHU1548.in", "r", stdin);
#endif // Phantom01 while (scanf("%d", &n)!=EOF) {
int k;
for (int i = ; i < n; i++) {
scanf("%d %d", &k, &a[i<<]);
if (k&) a[i<<|] = a[i<<];
else scanf("%d", &a[i<<|]);
}
slove();
}
return ;
}

下面是先建边,再跑2-SAT

数组存邻接表(本地随机了20组数据,跑了12秒, oj跑了3秒)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector> using namespace std; const int MAXN = ;
const int INF = (int)1e9+; int Edge[MAXN], next[MAXN*MAXN], to[MAXN*MAXN], used;
int a[MAXN];
bool mark[MAXN];
int S[MAXN], c;
int n; inline int myAbs(int x) {
return x> ? x : -x;
} inline void addEdge(int u, int v) {
next[used] = Edge[u];
to[used] = v;
Edge[u] = used++;
} void init() {
memset(Edge, -, sizeof(Edge));
used = ;
memset(mark, false, sizeof(mark));
memset(S, , sizeof(S));
c = ;
} bool dfs(int u, int k) {
if (mark[u^]) return false; //如果他的对立面和他同时被标记,那么这种情况不应该发生
if (mark[u]) return true; //如果他已经被标记 mark[u] = true; //他被标记
S[c++] = u; //这个点入栈
for (int p = Edge[u]; p != -; p = next[p]) if (!dfs(to[p], k))
return false;
return true;
} bool check(int k) {
init(); for (int i = ; i < n*; i++) {
for (int j = ; j < i; j++) {
if (i==j || i==(j^)) continue;
if (myAbs(a[i]-a[j])<k) {
addEdge(i^, j);
addEdge(j^, i);
}
}
} for (int i = ; i < n*; i += ) {
if (!mark[i] && !mark[i|]) { //如果这个点没有被标记
c = ;
if (!dfs(i, k)) { //如果x不能赋值为真
while (c>) mark[S[--c]] = false;
if (!dfs(i|, k)) return false; //如果x也不能赋值为假,那么无解
}
}
}
return true;
} void slove() {
int l = , r = INF, m;
while (l<r) {
m = (l+r)>>;
if (!check(m)) r = m;
else l = m+;
}
printf("%d\n", r-);
} int main() {
#ifdef Phantom01
freopen("WHU1548.in", "r", stdin);
#endif // Phantom01 while (scanf("%d", &n)!=EOF) {
int k;
for (int i = ; i < n; i++) {
scanf("%d %d", &k, &a[i<<]);
if (k&) a[i<<|] = a[i<<];
else scanf("%d", &a[i<<|]);
}
slove();
}
return ;
}

下面是vector存边的(本地跑了30秒)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector> using namespace std; const int MAXN = ;
const int INF = (int)1e9+; vector<int> Edge[MAXN];
int a[MAXN];
bool mark[MAXN];
int S[MAXN], c;
int n; inline int myAbs(int x) {
return x> ? x : -x;
} void init() {
for (int i = ; i < n*; i++)
Edge[i].clear();
memset(mark, false, sizeof(mark));
memset(S, , sizeof(S));
c = ;
} bool dfs(int u, int k) {
if (mark[u^]) return false; //如果他的对立面和他同时被标记,那么这种情况不应该发生
if (mark[u]) return true; //如果他已经被标记 mark[u] = true; //他被标记
S[c++] = u; //这个点入栈
for (int i = ; i < Edge[u].size(); i++) if (!dfs(Edge[u][i], k))
return false;
return true;
} bool check(int k) {
init(); for (int i = ; i < n*; i++) {
for (int j = ; j < i; j++) {
if (i==j || i==(j^)) continue;
if (myAbs(a[i]-a[j])<k) {
Edge[i^].push_back(j);
Edge[j^].push_back(i);
}
}
} for (int i = ; i < n*; i += ) {
if (!mark[i] && !mark[i|]) { //如果这个点没有被标记
c = ;
if (!dfs(i, k)) { //如果x不能赋值为真
while (c>) mark[S[--c]] = false;
if (!dfs(i|, k)) return false; //如果x也不能赋值为假,那么无解
}
}
}
return true;
} void slove() {
int l = , r = INF, m;
while (l<r) {
m = (l+r)>>;
if (!check(m)) r = m;
else l = m+;
}
printf("%d\n", r-);
} int main() {
#ifdef Phantom01
freopen("WHU1548.in", "r", stdin);
#endif // Phantom01 while (scanf("%d", &n)!=EOF) {
int k;
for (int i = ; i < n; i++) {
scanf("%d %d", &k, &a[i<<]);
if (k&) a[i<<|] = a[i<<];
else scanf("%d", &a[i<<|]);
}
slove();
}
return ;
}

WHU 1548 Home 2-SAT的更多相关文章

  1. 多边形碰撞 -- SAT方法

    检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理. 原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠.如果不重叠,则认为这两个多边形 ...

  2. hdu 1548 楼梯 bfs或最短路 dijkstra

    http://acm.hdu.edu.cn/showproblem.php?pid=1548 Online Judge Online Exercise Online Teaching Online C ...

  3. 三分 --- CSU 1548: Design road

    Design road Problem's Link:   http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1548 Mean: 目的:从(0,0)到 ...

  4. POJ 1548 (二分图+最小路径覆盖)

    题目链接:http://poj.org/problem?id=1548 题目大意:给出一张地图上的垃圾,以及一堆机器人.每个机器人可以从左->右,上->下.走完就废.问最少派出多少个机器人 ...

  5. hdu 1548 A strange lift

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1548 A strange lift Description There is a strange li ...

  6. hdu 1548 A strange lift 宽搜bfs+优先队列

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1548 There is a strange lift.The lift can stop can at ...

  7. HDU 1548 A strange lift (Dijkstra)

    A strange lift http://acm.hdu.edu.cn/showproblem.php?pid=1548 Problem Description There is a strange ...

  8. whu 1464 deal with numbers

    WHU 1464  deal with numbers 题意: 给你一串数字,对着串数字有三项操作: Minus a,b,c:对区间[a,b]总的每个数都减c. Division a,b,c:对区间[ ...

  9. POJ 3678 Katu Puzzle(2 - SAT) - from lanshui_Yang

    Description Katu Puzzle is presented as a directed graph G(V, E) with each edge e(a, b) labeled by a ...

随机推荐

  1. ajax返回数据时,如何将javascript值(通常为对象或数组)转为json字符串

    ajax获取值时,返回的数据为空时 alert后出现 [ ]; 用if语句判断时不为空,此时如何判断返回的数据是否为空.可将返回的值转化为json字符串. JSON.stringify() 方法用于将 ...

  2. dispatch_group_t踩过的坑

    如果想在dispatch_queue中所有的任务执行完成后在做某种操作,在串行队列中,可以把该操作放到最后一个任务执行完成后继续,但是在并行队列中怎么做呢.这就有dispatch_group 成组操作 ...

  3. 优动漫PAINT-紫藤花画法

    本教程分享一篇使用优动漫PAINT绘制一树梦幻的紫藤萝花教程,原文转载自优动漫官网. 小清新紫藤萝教程,就到这里啦!有兴趣的可以尝试画一画哦,软件下载:www.dongmansoft.com/xiaz ...

  4. 3ds Max实例教程:制作雪的材质

    导言: 本教程为大家讲解使用3ds MAX制作真实的雪材质制作过程,非常简单的教程,但个人觉得讲解的非常好,希望这套比较老的教程能给你带来帮助. 下面教程开始 雪的材质看似简单,其实它的制做并不是想像 ...

  5. java开发过程中几种常用算法

    排序算法 排序算法中包括:简单排序.高级排序 简单排序 简单排序常用的有:冒泡排序.选择排序.插入排序 冒泡排序代码如下: private static void bubbleSrot(int[] a ...

  6. ListNode的python 实现

    class Node(object): def __init__(self): self.val = None self.next = None class Node_handle(): def __ ...

  7. electron 新手教程 打包 exe

    1.安装nodejs(会自动安装npm) 2.桌面新建文件夹    your-app  (下面目录结构) your-app/ ├── package.json ├── main.js └── inde ...

  8. Maven搭建之后的设置

    Maven搭建之后的设置 1,设置环境变量M2_HOME=D:\Java\apache-maven-3.3.9, MAVEN_OPTS=-Xms128m -Xmx512m 在path中,添加D:\Ja ...

  9. HDU 2196 Computer(求树上每一个节点到其他点的最远距离)

    解题思路: 求出树的直径的两个端点.则树上每一个节点到其它点的最远距离一定是到这两个端点的距离中最长的那一个. #include <iostream> #include <cstri ...

  10. 在KVM中执行windows 10虚机(by quqi99)

    作者:张华  发表于:2015-12-22版权声明:能够随意转载.转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 ) KVM ...