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

题意:

  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. Shiro授权认证原理和流程

    先来张图: 这是一张shiro的功能图: Authentication: 身份认证/登录,验证用户是否拥有相应的身份 Authorization: 授权/权限验证,验证某个已认证的用户是否拥有某个权限 ...

  2. ActiveMQ学习笔记(6)----ActiveMQ整合Spring开发

    1. 添加依赖 spring 提供了对JMS的支持,需要添加Spring支持jms的包和Spring的核心包,如下: <dependency> <groupId>org.apa ...

  3. 洛谷 P2633 Count on a tree 主席树

    在一棵树上,我们要求点 $(u,v)$ 之间路径的第$k$大数. 对于点 $i$  ,建立 $i$  到根节点的一棵前缀主席树. 简单容斥后不难得出结果为$sumv[u]+sumv[v]−sumv[l ...

  4. java中,length,length(),size()区别

    length——数组的属性: length()——String的方法: size()——集合的方法:

  5. 版本号比较[versionCompare]

    /*** * 版本号比较 * @param v1 版本号a * @param v2 版本号b * @return -1代表不是合格版本号:0代表一样大.1 代表版本号a大于版本号b.2代表版本号b大于 ...

  6. 算法38---292. Nim游戏

    1.题目: 你和你的朋友,两个人一起玩 Nim游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头. 拿掉最后一块石头的人就是获胜者.你作为先手. 你们是聪明人,每一步都是最优解. 编写一个函 ...

  7. CF1029E Tree with Small Distances (贪心)

    题目大意:给你一棵边权为1的树,让你加入一些边,使得根节点(1号节点)到其他节点的最短距离不大于2 并没有想到贪心...... 正解的贪心思路是这样的 用一个堆维护当前距离最远的点,然后把根节点和它的 ...

  8. mybatis中 #跟$的区别

    #相当于对数据 加上 双引号,$相当于直接显示数据 1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sq ...

  9. Spring Boot基础教程》 第1节工具的安装和使用

    <Spring Boot基础教程> 第1节 工具的安装和使用 Spring Boot文档 https://qbgbook.gitbooks.io/spring-boot-reference ...

  10. sort排序到底怎么排序

    sort()方法 sort() 方法在适当的位置对数组的元素进行排序,并返回数组. <!DOCTYPE html> <html> <head> <meta c ...