POJ 3683 Priest John's Busiest Day / OpenJ_Bailian 3788 Priest John's Busiest Day(2-sat问题)
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问题)的更多相关文章
- POJ 3683 Priest John's Busiest Day(2-SAT+方案输出)
Priest John's Busiest Day Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10010 Accep ...
- POJ 3683 Priest John's Busiest Day (2-SAT)
Priest John's Busiest Day Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6900 Accept ...
- 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 ...
- Priest John's Busiest Day(POJ 3683)
原题如下: Priest John's Busiest Day Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 12162 ...
- POJ 3683 Priest John's Busiest Day (2-SAT+输出可行解)
题目地址:POJ 3683 第一次做须要输出可行解的题目. . .大体思路是先用强连通来推断是否有可行解,然后用逆序建图.用拓扑排序来进行染色.然后输出可行解. 详细思路见传送门 由于推断的时候少写了 ...
- poj 3683(2-sat+拓扑排序)
Priest John's Busiest Day Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 11127 Accep ...
- 2-SAT的小总结(POJ 3683 POJ 3207)
记住几个最重要的公式: xANDy=0<=>(x=>y′)AND(y=>x′) xANDy=1<=>(x′=>x)AND(y′=>y) xORy=0&l ...
- poj - 3683 - Priest John's Busiest Day(2-SAT)
题意:有N场婚礼,每场婚礼的开始时间为Si,结束时间为Ti,每场婚礼有个仪式,历时Di,这个仪式要么在Si时刻开始,要么在Ti-Di时刻开始,问能否安排每场婚礼举行仪式的时间,使主持人John能参加所 ...
- POJ 3683 Priest John's Busiest Day (2-SAT)
题意:有n对新人要在同一天结婚.结婚时间为Ti到Di,这里有时长为Si的一个仪式需要神父出席.神父可以在Ti-(Ti+Si)这段时间出席也可以在(Di-Si)-Si这段时间.问神父能否出席所有仪式,如 ...
随机推荐
- C#中的委托(一)
一.委托 把方法作为参数传给其他方法: 二.声明委托 在C#中使用一个类时,分两个阶段.首先,需要去定义一个类,然后实例化类的一个对象(只需要静态方法除外). 使用委托也需要经过这2个步骤,首先必须定 ...
- C++ STL快速入门
在数月之前的机试中第一次体验到STL的威力,因为自己本来一直在用C语言做开发,很多数据结构都是自己造的,比如链表.队列等,第一次接触C++ STL后发现这些数据结构都已经给我提供好了,我直接拿去调用就 ...
- vmware和centOS的安装
如果勾上了,会立即在本机开辟20g的空间,需要很长时间 选择电脑中ISO镜像的位置,之后点击开启虚拟机! 这个密码是root用户的密码!管理员密码! 可以选择我们的Minimal没有界面的!
- Vue 犯罪指南:TypeError: Right-hand side of 'instanceof' is not an object
背景:在迁移项目从 Vue1.x 到 Vue2.x 时,改动没有过脑子,导致翻车.
- 高性能队列Disruptor系列1--传统队列的不足
在前一篇文章Java中的阻塞队列(BlockingQueue)中介绍了Java中的阻塞队列.从性能上我们能得出一个结论:数组优于链表,CAS优于锁.那么有没有一种队列,通过数组的方式实现,而且采用无锁 ...
- 学习笔记TF022:产品环境模型部署、Docker镜像、Bazel工作区、导出模型、服务器、客户端
产品环境模型部署,创建简单Web APP,用户上传图像,运行Inception模型,实现图像自动分类. 搭建TensorFlow服务开发环境.安装Docker,https://docs.docker. ...
- 《Python编程从入门到实践》_第六章_字典
一个简单的字典 #用户信息 user = {','city':'shanghai'} print(user['name']) print(user['age']) print(user['city'] ...
- JS/jQ常用宽高及应用
关于js的宽高,随便一搜就是一大堆.这个一大堆对我来说可不是什么好事,看的头都大了.所以今天就总结了一些比较会常用的,并说明一下应用场景. 先来扯一下documentElement和body的微妙关系 ...
- JS采用ActiveXObject实现用户在提交表单时屏蔽敏感词的功能
本例中敏感词ciku.txt放在C盘根目录下,采用的ActiveXObject插件获取本地文件内容.使用此插件不需网上下插件,直接用如下js代码即可. 浏览器需修改interner安全选项的级别,启用 ...
- js函数中的BOM和DOM
BOM 浏览器对象模型 screen对象 console.log(screen.width);// 屏幕宽度 console.log(screen.height);// 屏幕高度 console.l ...