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. MongoDB系列:把mongodb作为windows的服务来启动

    1.首先切换到mongodb安装目录下的bin目录,在控制台直接运行以下命令 "C:\Program Files\MongoDB\Server\3.0\bin\mongod.exe" ...

  2. MidpointRounding 枚举值简要说明

    1. MidpointRounding.AwayFromZero 当小数点后取舍时5 时会取绝对值大的如 4.5 会取5 及正常的4舍5入. -- 官方解释翻译解释取绝对值小值感觉反译错了. 2.Mi ...

  3. [转]DevExpress GridControl 关于使用CardView的一点小结

    最近项目里需要显示商品的一系列图片,打算用CardView来显示,由于第一次使用,遇到许多问题,发现网上这方面的资源很少,所以把自己的一点点实际经验小结一下,供自己和大家以后参考. 1.选择CardV ...

  4. [编织消息框架][网络IO模型]aio

    asynchronous I/O (the POSIX aio_functions)—————异步IO模型最大的特点是 完成后发回通知. [编织消息框架][网络IO模型]NIO(select and ...

  5. extj6.0写增删查改(1)-------查询

    本文主要实现的效果是:点击查询按钮,根据form中的条件,在Grid中显示对应的数据(如果form为空,显示全部数据) 一.静态页面 1.查询按钮 { text:'查询', handler: 'onS ...

  6. Android SQLite与ListView的简单使用

    2017-04-25 初写博客有很多地方都有不足,希望各位大神给点建议. 回归主题,这次简单的给大家介绍一下Android SQLite与ListView的简单使用sqlite在上节中有介绍,所以在这 ...

  7. 为linux安装xen-tools提示/dev/xvdd does not exist

    看样子百度还是不如google啊.百度上找到的信息完全无用.google上却给我找到了... 1:当/dev/xvdd does not exist错误出现时,可以尝试下 mount /dev/cdr ...

  8. Expression表达式树动态查询

    在进行数据列表的查询中,我们通常会使用两种方式进行查询: linq查询 数据库sql语句查询 这样固然可以实现查询,本人之前也都是这么做的,因为查询的条件很少.使用linq,可以将所有的查询条件的属性 ...

  9. 对象克隆(clone)实例详解

    <?php class Staff { public $name; public $age; public $salary; public function __construct($name, ...

  10. Linux之定时任务

    定时任务Crond介绍 Crond是linux系统中用来定期执行命令/脚本或指定程序任务的一种服务或软件,一般情况下,我们安装完Centos5/6 linux操作系统之后,默认便会启动Crond任务调 ...