poj3683

题意

n对新人举行婚礼,婚礼在不同时间段但可能重叠,婚礼有开始(Si)、结束(Ti)、仪式举行时间(Di),问能否给出一种举行方案,使得神父能参加所有的婚礼并举行仪式。

分析

xi为真 <=> 在开始时举行仪式,

xj为假 <=> 在结束时举行仪式。

设x' 为 非x。(若 x 为真,则 x' 为假)

xi -> xj 表示 xi 为真则 xj 为真。(xi xj 连边)

对于结婚仪式 i 和 j ,如果 Si ~ Si+Di 和 Sj ~ Sj+Dj 冲突,就有 xi' or xj' ,这种情况即 xi -> xj' ,xj -> xi' 。(xi 和 xj 不能同时选,即选择一个,那么选了 xi 后 就会选择到 xj' ,表示不选 xj。)

如果 Si ~ Si+Di 和 Tj-Dj ~ Dj 冲突,有 xi' or xj ,即 xi -> xj,xj' -> xi' 。

如果 Ti-Di ~ Ti 和 Sj ~ Sj+Dj 冲突,有 xi or xj' ,即 xi' -> xj',xj -> xi 。

如果 Ti-Di ~ Ti 和 Tj-Dj ~ Dj 冲突 ,有 xi or xj ,即 xi' -> xj ,xj' -> xi 。

代码参照《 挑战程序设计竞赛》,网上的代码大多是按照论文进行模拟?

书中有个步骤比较疑惑,打印可行解时,

x 所在的强连通分量的拓扑序在 x' 所在的强连通分量之后 <=> x 为真。

一点理解:拓扑序靠后的出度小,越不会影响后面的选择?

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
typedef long long ll; using namespace std; const int MAXN = 2e3 + 10;
int n, m; // 点、边
int vis[MAXN];
int flag[MAXN]; // 所属强连通分量的拓扑序
vector<int> G[MAXN], rG[MAXN];
vector<int> vs; // 后序遍历顺序的顶点列表
void addedge(int x, int y)
{
G[x].push_back(y); // 正向图
rG[y].push_back(x); // 反向图
}
void dfs(int u)
{
vis[u] = 1;
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(!vis[v]) dfs(v);
}
vs.push_back(u);
}
void rdfs(int u, int k)
{
vis[u] = 1;
flag[u] = k;
for(int i = 0; i < rG[u].size(); i++)
{
int v = rG[u][i];
if(!vis[v]) rdfs(v, k);
}
}
int scc() // 强连通分量的个数
{
vs.clear();
memset(vis, 0, sizeof vis);
for(int i = 1; i <= n; i++) // [1...n]
if(!vis[i]) dfs(i);
memset(vis, 0, sizeof vis);
int k = 0;
for(int i = vs.size() - 1; i >= 0; i--)
if(!vis[vs[i]]) rdfs(vs[i], k++);
return k;
} int S[MAXN], D[MAXN], T[MAXN]; void solve()
{
int N = n;
n = 2 * n;
for(int i = 1; i <= n; i++)
{
G[i].clear();
rG[i].clear();
}
for(int i = 1; i <= n; i++) // 枚举、连边
{
for(int j = 1; j < i; j++)
{
if(min(S[i] + D[i], S[j] + D[j]) > max(S[i], S[j]))
{
// xi -> xj' ,xj -> xi'
addedge(i, j + N);
addedge(j, i + N);
}
if(min(S[i] + D[i], T[j]) > max(S[i], T[j] - D[j]))
{
// xi -> xj,xj' -> xi'
addedge(i, j);
addedge(j + N, i + N);
}
if(min(T[i], S[j] + D[j]) > max(S[j], T[i] - D[i]))
{
// xi' -> xj',xj -> xi
addedge(i + N, j + N);
addedge(j, i);
}
if(min(T[i], T[j]) > max(T[i] - D[i], T[j] - D[j]))
{
// xi' -> xj ,xj' -> xi
addedge(i + N, j);
addedge(j + N, i);
}
}
}
scc(); // 判断可行性
for(int i = 1; i <= N; i++)
{
if(flag[i] == flag[N + i])
{
puts("NO");
return;
}
} // 输出可行解
puts("YES");
for(int i = 1; i <= N; i++)
{
if(flag[i] > flag[i + N]) // 在仪式开始时举行
printf("%02d:%02d %02d:%02d\n", S[i] / 60, S[i] % 60, (S[i] + D[i]) / 60, (S[i] + D[i]) % 60);
else
printf("%02d:%02d %02d:%02d\n", (T[i] - D[i]) / 60, (T[i] - D[i]) % 60, T[i] / 60, T[i] % 60);
}
} int main()
{
while(~scanf("%d", &n))
{
for(int i = 1; i <= n; i++)
{
int x1, y1, x2, y2;
char p, q;
scanf("%02d:%02d %02d:%02d %d", &x1, &y1, &x2, &y2, &D[i]);
S[i] = x1 * 60 + y1;
T[i] = x2 * 60 + y2;
}
solve();
}
return 0;
}

poj3683的更多相关文章

  1. 2-sat——输出方案poj3683

    一篇讲的详细的博客 https://blog.csdn.net/Hawo11/article/details/74908233 缩点后为什么要建立反图? 如果是按原图处理,选择一个点之后要把所有其后续 ...

  2. 2-sat 输出任意一组可行解&拓扑排序+缩点 poj3683

    Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8170   Accept ...

  3. poj3683 Priest John's Busiest Day

    2-SAT 输出可行解 找可行解的方案就是: 根据第一次建的图建一个反图..然后求逆拓扑排序,建反图的原因是保持冲突的两个事件肯定会被染成不同的颜色 求逆拓扑排序的原因也是为了对图染的色不会发生冲突, ...

  4. poj3683 Priest John's Busiest Day

    2-SAT. 读入用了黄学长的快速读入,在此膜拜感谢. 把每对时间当作俩个点.如果有交叉代表相互矛盾. 然后tarjan缩点,这样就能得出当前的2-SAT问题是否有解. 如果有解,跑拓扑排序就能找出一 ...

  5. POJ3683 Falsita

    http://poj.org/problem?id=3683 思路:2-SAT,输出任意一组方案,O(m+n) #include<cstdio> #include<iostream& ...

  6. 【POJ3683】Priest John's Busiest Day

    题目 John is the only priest in his town. September 1st is the John's busiest day in a year because th ...

  7. Poj3683:Priest John's Busiest Day

    题意 n对夫妻要结婚,第i对夫妻结婚的婚礼持续时间为[Si, Ti],他们会举行一个仪式,仪式时间为Di,这个仪式只能举行在开头或者结尾举行,要么[Si, Si+Di],要么[Ti-Di, Ti],然 ...

  8. POJ3683 Priest John's Busiest Day(2-SAT)

    Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11049   Accepted: 3767   Special Judge ...

  9. poj3683(2-SAT 求任意方案)

    基础的2-SAT求任意方案的题目. Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissi ...

随机推荐

  1. SQL Server 死锁概念和分析

    锁的概念 锁是什么 锁是数据库中在并发操作情形下保护资源的机制.通常(具体要看锁兼容性)只有锁的拥有者才能对被锁的资源进行操作,从而保证数据一致性. 锁的概念可分为几部分 锁资源(锁住什么) 锁模式( ...

  2. 使用canvas实现擦除效果

    HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像.画布是一个矩形区域,您可以控制其每一像素.canvas 拥有多种绘制路径.矩形.圆形.字符以及添加图像的方法. html ...

  3. 大数据及hadoop相关知识介绍

    一.大数据的基本概念 1.1什么是大数据 互联网企业是最早收集大数据的行业,最典型的代表就是Google和百度,这两个公司是做搜索引擎的,数量都非常庞大,每天都要去把互联网上的各种各样的网页信息抓取下 ...

  4. 详解Java反射机制

    反射是程序在运行状态下,动态的获取某个类的内部信息的一种操作.例如:类名,包名,所有属性的集合,所有方法的集合,构造方法的集合等.该操作发生在程序的运行时状态,所以编译器管不着有关反射的一些代码,通常 ...

  5. 使用Nodejs进行反向代理

    在实际工程开发中,会有前后端分离的需求. 为了平滑的完成前端请求到后端各个独立服务,需要一个中间件实现请求转发的功能,利用Nginx可以实现,在这里,使用nodejs实现一个反向代理服务器.   实际 ...

  6. 【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 F - Piggy-Bank 【完全背包问题】

    https://vjudge.net/contest/68966#problem/F http://blog.csdn.net/libin56842/article/details/9048173 # ...

  7. 【lucene系列学习四】使用IKAnalyzer分词器实现敏感词和停用词过滤

    Lucene自带的中文分词器SmartChineseAnalyzer不太好扩展,于是我用了IKAnalyzer来进行敏感词和停用词的过滤. 首先,下载IKAnalyzer,我下载了 然后,由于IKAn ...

  8. oracle表信息

    获取表: select table_name from user_tables; //当前用户的表 select table_name from all_tables; //所有用户的表 select ...

  9. Modelsim使用笔记(一个完成工程的仿真)

    这学期在玩Altera的板子,不不, 现在应该叫intel PSG.在QuartusII13.0上老喜欢用modelsim_ae做仿真,小工程用起来也方便,但是我做IIC配置摄像头的时序仿真时,就显得 ...

  10. selenium 利用testNG对异常进行自动截图

    哈哈哈,很久没写博客了,懒了. 因为一些原因最近需要把监听事件重新整理一下,开始没细想,直接copy网上的,其实结果发现报错很多,或者是达不到效果,然后把之前的代码翻出来,仔细看了一下.下面给一些需要 ...