WHU 1548 Home 2-SAT
---恢复内容开始---
题意:
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的更多相关文章
- 多边形碰撞 -- SAT方法
检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理. 原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠.如果不重叠,则认为这两个多边形 ...
- hdu 1548 楼梯 bfs或最短路 dijkstra
http://acm.hdu.edu.cn/showproblem.php?pid=1548 Online Judge Online Exercise Online Teaching Online C ...
- 三分 --- CSU 1548: Design road
Design road Problem's Link: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1548 Mean: 目的:从(0,0)到 ...
- POJ 1548 (二分图+最小路径覆盖)
题目链接:http://poj.org/problem?id=1548 题目大意:给出一张地图上的垃圾,以及一堆机器人.每个机器人可以从左->右,上->下.走完就废.问最少派出多少个机器人 ...
- hdu 1548 A strange lift
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1548 A strange lift Description There is a strange li ...
- 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 ...
- HDU 1548 A strange lift (Dijkstra)
A strange lift http://acm.hdu.edu.cn/showproblem.php?pid=1548 Problem Description There is a strange ...
- whu 1464 deal with numbers
WHU 1464 deal with numbers 题意: 给你一串数字,对着串数字有三项操作: Minus a,b,c:对区间[a,b]总的每个数都减c. Division a,b,c:对区间[ ...
- 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 ...
随机推荐
- C++之易混淆知识点一-----static详解
1.const.mutable与volatile的区别:const表明内存被初始化以后,程序将不能对它进行修改.volatile则表明,即使程序代码没有对内存单元进行修改,但是里面的值也可能会发生变化 ...
- Codeforces 959E. Mahmoud and Ehab and the xor-MST 思路:找规律题,时间复杂度O(log(n))
题目: 解题思路 这题就是0,1,2...n-1总共n个数字形成的最小生成树. 我们可以发现,一个数字k与比它小的数字形成的异或值,一定可以取到k与所有正整数形成的异或值的最小值. 要计算n个数字的情 ...
- Servlet学习(一)——Servlet的生命周期、执行过程、配置
1.什么是Servlet Servlet 运行在服务端的Java小程序,是sun公司提供一套规范(接口),用来处理客户端请求.响应给浏览器的动态资源.但servlet的实质就是java代码,通过jav ...
- hiho 1620 - 股票价格3 - 无限制的单调队列?
题目链接 小Hi最近在关注股票,为了计算股票可能的盈利,他获取了一只股票最近N天的价格A1~AN. 小Hi想知道,对于第i天的股票价格Ai,几天之后股价会第一次超过Ai. 假设A=[69, 73, 6 ...
- SpringBoot 获取客户端 ip
/** * 获取客户端ip地址 * @param request * @return */ public static String getCliectIp(HttpServletRequest re ...
- 注解@SuppressWarnings
在JAVA中注解@SuppressWarnings("deprecation")的Deprecation是什么意思 过期的 @SuppressWarnings("depr ...
- ueditor 编辑器,自定义图片上传
<div> <h1>完整demo</h1> <form method="post" name="form"> & ...
- 如何发布到NPM上(转)
简要:这篇文章介绍了如何讲自己的包发布到NPM上,马克一下,将来有用 ... npm包发布 发布npm包,更方便以后下载使用. 我们已经把插件代码上传到github上面了,那么我们是否可以也做成一个n ...
- 永远不要在MySQL中使用“utf8”
最近我遇到了一个 bug,我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一个 UTF-8 字符串,然后出现了一个离奇的错误: Incorrect string value: ‘ ...
- mariadb数据库基础知识及备份
数据库介绍 1.什么是数据库? 简单的说,数据库就是一个存放数据的仓库,这个仓库是按照一定的数据结构(数据结构是指数据的组织形式或数据之间的联系)来组织,存储的,我们可以通过数据库提供的多种方法来管理 ...