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

题意:

  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. (转载) Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

    Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题 标签: scrollviewandroid滑动嵌套 2015-07-16 17:24 1112 ...

  2. PostgreSQL 索引膨胀

    索引膨胀,主要针对B-tree而言 索引膨胀的几个来源: 大量删除发生后,导致索引页面稀疏,降低了索引的使用效率: PG9.0之前的版本,vacuum full会同样导致索引页面稀疏: 长时间运行的事 ...

  3. OpenGL编程(七)3D模型的深度(z轴)检测

    下图是我们要修改后的效果图: 一.深度检测 1.模型Z轴显示有问题: 上一次试验中,如果认真留意,会发现一个问题.当控制锥体在左右或上下旋转时,你会发现锥体看起来是在+-180度之间来回摆动,而不是3 ...

  4. Unknown column 't_user.id' in 'where clause'(通过字段名删除不了数据)

    创建员工信息表t_user CREATE TABLE t_user( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(20) , passwor ...

  5. PKI和加密,散列算法

    Day 11-PKI和加密,散列算法 PKI(Public Key Infrastructure公钥基础设施) 1 PKI(Public Key Infrastructure公钥基础设施)回顾学习 - ...

  6. codeforces 914 D Bash and a Tough Math Puzzle

    #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #i ...

  7. hook中ref使用

    hook使用ref 父组件: 引入                  useRef 声明ref的名字     const dateRef = useRef() 复值给组件         ref={d ...

  8. Mysql学习总结(29)——MySQL中CHAR和VARCHAR

    MySQL数据库的字符(串)类不要以为字符类型就是CHAR,CHAR和VARCHAR的区别在于CHAR是固定长度,只要你定义一个字段是CHAR(10),那么不论你存储的数据是否达到了10个字节,它都要 ...

  9. dos2unix和unix2dos命令使用【转】

    dos2unix, unix2dos 用来实现 DOS <=> UNIX text file 转换 aptitude install sysutils 行末: DOS 格式 0d 0a U ...

  10. 小A点菜 水题 dp 背包

    基本上还是01背包,首先注意必须正好花光钱,所以初始化时除了dp[0]以外其他都要设置成inf,然后因为求方案数,所以基本方程为dp[i] = dp[i-x] + dp[i],再根据inf进行一些特殊 ...