POJ 3683 Priest John's Busiest Day / OpenJ_Bailian 3788 Priest John's Busiest Day(2-sat问题)

Description

John is the only priest in his town. September 1st is the John's busiest day in a year because there is an old legend in the town that the couple who get married on that day will be forever blessed by the God of Love. This year N couples plan to get married on the blessed day. The i-th couple plan to hold their wedding from time Si to time Ti. According to the traditions in the town, there must be a special ceremony on which the couple stand before the priest and accept blessings. The i-th couple need Di minutes to finish this ceremony. Moreover, this ceremony must be either at the beginning or the ending of the wedding (i.e. it must be either from Si to Si + Di, or from Ti - Di to Ti). Could you tell John how to arrange his schedule so that he can present at every special ceremonies of the weddings.

Note that John can not be present at two weddings simultaneously.

Input

The first line contains a integer N ( 1 ≤ N ≤ 1000).

The next N lines contain the Si, Ti and Di. Si and Ti are in the format of hh:mm.

Output

The first line of output contains "YES" or "NO" indicating whether John can be present at every special ceremony. If it is "YES", output another N lines describing the staring time and finishing time of all the ceremonies.

Sample Input

2

08:00 09:00 30

08:15 09:00 20

Sample Output

YES

08:00 08:30

08:40 09:00

Http

POJ:https://vjudge.net/problem/POJ-3683

OpenJ_Bailian:https://vjudge.net/problem/OpenJ_Bailian-3788

Source

2-sat

题目大意

给定n个活动及其最早开始、最迟结束及持续时间,要求活动要么在最早开始时开始,要么在最迟结束时结束。求如何安排这些活动使得这些活动都可以参加。

解决思路

对于每一个活动,因为都有两种时间安排方式,不妨将其看做2-sat中一组中的两个元素。用i表示在最早开始时开始,则用i+n表示最迟结束时结束。那么扫描所有的活动,若i与j冲突(即时间有重合),建边i->j+n,若i与j+n冲突,建边i->j,对于i+n与j的情况类似。然后tarjan缩点,判断可行性,若可行则继续,否则直接输出NO结束。至此,所有做法与这道题是一致的。

但是因为这道题要求输出结果而不只是判断是否成立,所以接下来我们要想办法找到一组解。为什么只是一组解呢?因为POJ非常良心的给了Special judge,所以不需要字典序。

整理一下思路,现在我们要讲讲2-sat比较深入的部分了!(咳咳……)

其实关于2-sat的建图,一直有一个比较显著的性质没有讲,那就是2-sat图的对称性

回顾一下我们建图的过程,我们说如果i与j矛盾,那么连边i->j',j->i'。注意这也就意味着若存在边x->y,则一定存在边y'->x'

推广一下,缩点后的边一定也具有对称性

这里借用一下伍昱 由对称性解2-sat问题.ppt中的图说明一下对称性:

一般情况:



缩点后:



更加一般的情况:

所以说如果我们假设选择了i(不论是点还是强连通分量),那么就要将其对点i'标记为不选择,并且将不选择进行反向传递。

那么为了方便起见,我们在Tarjan缩点后将原图反置过来,这样就可以直接反着跑了。

最后一个问题是,按照怎样的一个顺序进行选择呢?

答案:拓扑排序的顺序(反过来的图)

因为在Tarjan缩点后,不会存在环了,所以可以按照拓扑序列依次选择。

另外需要注意的是,Tarjan缩点后的强连通分量的点不具备对称性,需要用另一个数组(我的代码里用的是Opp)存下与之相对的点的强联通编号,这样才能进行有关对称性的操作。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<stack>
#include<queue>
using namespace std; class TIME//记录开始时间和结束时间
{
public:
int t1,t2;
}; const int maxN=4000;
const int inf=2147483647; int n;
TIME T[maxN];
vector<int> E[maxN];//原图
vector<int> E2[maxN];//缩点并反向后的图
//tarjan Tarjan中要用到的变量,不解释
int cnt=0;
int dfn[maxN];
int low[maxN];
bool instack[maxN];
stack<int> S;
//LTK 连通块
int LTKcnt=0;//连通块数量
int Belong[maxN];//原来的点所属的强联通分量编号
int Opp[maxN];//存下与x所属的强连通分量对立的x'所属的强连通分量的编号
//Top_sort
int InDegree[maxN];//入读
queue<int> Q;
int color[maxN];//标记选择或不选择,-1表示还未进行标记,0表示不选择,1表示选择 void Read_and_Init();
bool Repeat(int a,int b);//判断时间是否重复
void Link(int a,int b);//连接a和b
void tarjan(int u);
void Top_sort();//拓扑排序 int main()
{
while(cin>>n)
{
Read_and_Init();
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
for (int i=1;i<=n*2;i++)
if (dfn[i]==0)
tarjan(i); bool ok=1;
for (int i=1;i<=n;i++)
{
if (Belong[i]==Belong[i+n])//判断可行性
{
ok=0;
break;
}
Opp[Belong[i]]=Belong[i+n];//同时存下缩点后相对的点编号
Opp[Belong[i+n]]=Belong[i];
}
if (ok)
{
cout<<"YES"<<endl;
Top_sort();
for (int i=1;i<=n;i++)
if (color[Belong[i]]==1)//如果第i个活动选择最早开始是开始
{
printf("%.2d:%.2d %.2d:%.2d\n",T[i].t1/60,T[i].t1%60,T[i].t2/60,T[i].t2%60);
}
else //if (color[Belong[i]]==0) 否则则是最晚结束时结束
printf("%.2d:%.2d %.2d:%.2d\n",T[i+n].t1/60,T[i+n].t1%60,T[i+n].t2/60,T[i+n].t2%60);
}
else
cout<<"NO"<<endl;
}
return 0;
} void Read_and_Init()
{
int a,b,c,d,e;
//cin>>n;
for (int i=1;i<=n*2;i++)
{
E[i].clear();
E2[i].clear();
}
cnt=0;
LTKcnt=0;
while (!Q.empty())
Q.pop();
while (!S.empty())
S.pop();
for (int i=1;i<=n;i++)
{
scanf("%d:%d %d:%d %d",&a,&b,&c,&d,&e);//注意转换格式
a=a*60+b;
c=c*60+d;
T[i].t1=a;
T[i].t2=a+e;
T[i+n].t1=c-e;
T[i+n].t2=c;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j)//判断两个活动是否冲突
{
if (Repeat(i,j))
Link(i,j+n);
if (Repeat(i,j+n))
Link(i,j);
if (Repeat(i+n,j))
Link(i+n,j+n);
if (Repeat(i+n,j+n))
Link(i+n,j);
}
return;
} bool Repeat(int a,int b)
{
if ((T[a].t1>=T[b].t2)||(T[a].t2<=T[b].t1))
return 0;
return 1;
} void Link(int a,int b)
{
E[a].push_back(b);
} void tarjan(int u)
{
cnt++;
dfn[u]=low[u]=cnt;
instack[u]=1;
S.push(u);
for (int i=0;i<E[u].size();i++)
{
int v=E[u][i];
if (dfn[v]==0)
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else
if (instack[v]==1)
low[u]=min(low[u],dfn[v]);
}
if (dfn[u]==low[u])
{
int v;
LTKcnt++;
do
{
v=S.top();
S.pop();
instack[v]=0;
Belong[v]=LTKcnt;
}
while (u!=v);
}
return;
} void Top_sort()
{
memset(InDegree,0,sizeof(InDegree));
memset(color,-1,sizeof(color));
for (int i=1;i<=n*2;i++)//将原图缩点后反置
for (int j=0;j<E[i].size();j++)
{
int v=E[i][j];
if (Belong[i]!=Belong[v])
{
E2[Belong[v]].push_back(Belong[i]);
InDegree[Belong[i]]++;//同时统计入度(拓扑排序要用)
}
}
for (int i=1;i<=LTKcnt;i++)
if (InDegree[i]==0)
Q.push(i);//把入度为0的加入队列
do
{
int u=Q.front();
Q.pop();
if (color[u]==-1)//如果这个点还没有标记,则把其标记为1(选择),对立点标记为0(不选择)
{
color[u]=1;
color[Opp[u]]=0;
}
for (int i=0;i<E2[u].size();i++)
{
InDegree[E2[u][i]]--;
if (InDegree[E2[u][i]]==0)
Q.push(E2[u][i]);//加入新的点
}
}
while (!Q.empty());
return;
}

POJ 3683 Priest John's Busiest Day / OpenJ_Bailian 3788 Priest John's Busiest Day(2-sat问题)的更多相关文章

  1. POJ 3683 Priest John's Busiest Day(2-SAT+方案输出)

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

  2. POJ 3683 Priest John's Busiest Day (2-SAT)

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

  3. POJ 3683 Priest John's Busiest Day(2-SAT 并输出解)

    Description John is the only priest in his town. September 1st is the John's busiest day in a year b ...

  4. Priest John's Busiest Day(POJ 3683)

    原题如下: Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 12162   ...

  5. POJ 3683 Priest John&#39;s Busiest Day (2-SAT+输出可行解)

    题目地址:POJ 3683 第一次做须要输出可行解的题目. . .大体思路是先用强连通来推断是否有可行解,然后用逆序建图.用拓扑排序来进行染色.然后输出可行解. 详细思路见传送门 由于推断的时候少写了 ...

  6. poj 3683(2-sat+拓扑排序)

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

  7. 2-SAT的小总结(POJ 3683 POJ 3207)

    记住几个最重要的公式: xANDy=0<=>(x=>y′)AND(y=>x′) xANDy=1<=>(x′=>x)AND(y′=>y) xORy=0&l ...

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

    题意:有N场婚礼,每场婚礼的开始时间为Si,结束时间为Ti,每场婚礼有个仪式,历时Di,这个仪式要么在Si时刻开始,要么在Ti-Di时刻开始,问能否安排每场婚礼举行仪式的时间,使主持人John能参加所 ...

  9. POJ 3683 Priest John's Busiest Day (2-SAT)

    题意:有n对新人要在同一天结婚.结婚时间为Ti到Di,这里有时长为Si的一个仪式需要神父出席.神父可以在Ti-(Ti+Si)这段时间出席也可以在(Di-Si)-Si这段时间.问神父能否出席所有仪式,如 ...

随机推荐

  1. C# 类型基础(中)

    前一篇文章中我们讲到了值类型和引用类型的一些区别,那这篇我们将深入的分析一下到底有什么不一样 先总结一下两者的差别: 黄金法则: 1.引用类型总是被分配到托管堆上. 2.值类型总是分配到它声明的地方: ...

  2. SQL万能语句-经典操作

    一.基础 1.说明:创建数据库CREATE DATABASE database-name 2.说明:删除数据库drop database dbname3.说明:备份sql server--- 创建 备 ...

  3. cookie笔记(一)

    1.浏览器存储信息的一个工具 2.容量有限,每个域名一般50个.详情 3.形式:键=值: 4.获取:document.cookie; 5.设置:document.cookie="uid=we ...

  4. Rhythmbox音乐播放器常见问题

    一.歌名中文乱码 对于所有用gstreamer做后端的播放器,如Rhythmbox, 设置如下的环境变量后即可正确读取mp3中GBK编码的id3 tag. export GST_ID3_TAG_ENC ...

  5. android studio IDE 下,设置ACTIVITY全屏

    因为ANDROID STUDIO的JAVA类是继承AppCompatActivity的 ,所以常规的全屏设置并不管用.如果要设置全屏,请参照如下代码/ 1/首先,打开AndroidManifest.x ...

  6. js 动态 key value

    问题描述: 如果var mykey = 'a'; 我们试图 a = {mykey: 'b'} 来达到 a = { 'a': 'b'}的效果,但是mykey直接被作为键值,无法达到要求 解决办法: a ...

  7. VMware安装CentOS 提示:已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。解决方案

    安装虚拟机遇到错误: 在网上查了查资料,发现CPU支持VT技术的就能支持vmware中安装64位虚拟机. 以下是操作步骤: 1)到网上下载一个securable.exe,测试以下机器是否支持VT. l ...

  8. 关于java反射获取泛型

    public class Test<T> { private final TypeToken<T> typeToken = new TypeToken<T>(get ...

  9. mybatis if test加筛选条件

    最近在项目使用mybatis中碰到个问题 <if test="type=='y'"> and status = 0 </if> 当传入的type的值为y的时 ...

  10. Java学习笔记--脚本语言支持API

    Java语言的动态性之脚本语言支持API 随着Java平台的流行,很多的脚本语言(scripting language)都可以运行在Java虚拟机啊上,其中比较流行的有JavaScript.JRuby ...