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这段时间.问神父能否出席所有仪式,如 ...
随机推荐
- 细说"回车"和"换行"的故事
引言 最近在php还有c#以及memcache的shell当中经常看到\r\n的写法,刚开始还没注意, 不过后面感觉这样写有些不对头,\r表示回车 \n表示换行,那这样不是换行了两次吗? 为了解决疑 ...
- stm之SPI通信协议
SPI (Serial Peripheral interface),顾名思义就是串行外围设备接口.SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为P ...
- js实现分页
<html> <head> <meta charset='utf-8'> <script type="text/javascript" s ...
- 【web前端开发】浏览器兼容性处理
1.居中问题div里的内容,IE默认为居中,而FF默认为左对齐,可以尝试增加代码margin: 0 auto;2.高度问题两上下排列或嵌套的div,上面的div设置高度(height),如果div里的 ...
- 设计模式一:关于C++写观察者模式的一些收获
先贴上部分代码: #include "stdafx.h" #include<iostream> #include<string> #include<v ...
- Syntax error on tokens, delete these tokens.问题解决
问题:Syntax error on tokens, delete these tokens.(在标记语法错误,删除这些标记) 原因:存在中文字符或者符号(包括空格):单引号.双引号不匹配:复制的代码 ...
- Pycon 2017: Python可视化库大全
本文首发于微信公众号“Python数据之道” 前言 本文主要摘录自 pycon 2017大会的一个演讲,同时结合自己的一些理解. pycon 2017的相关演讲主题是“The Python Visua ...
- python大规模爬取京东
python大规模爬取京东 主要工具 scrapy BeautifulSoup requests 分析步骤 打开京东首页,输入裤子将会看到页面跳转到了这里,这就是我们要分析的起点 我们可以看到这个页面 ...
- tcp/ip详解 卷1 -- 协议概述
第一章 概述 分层 TCP/IP 通常被认为是一个四层协议系统. 每一层负责不同的功能. 链路层, 也成为数据链路层或者网络接口层. 通常包括 操作系统中的设备驱动程序和计算机中对应的网络接口卡. 主 ...
- arcgis api for js入门开发系列十叠加SHP图层
上一篇实现了demo的热力图,本篇新增叠加SHP图层,截图如下: 叠加SHP图层效果实现的思路如下:利用封装的js文件,直接读取shp图层,然后转换geojson,最后通过arcgis api来解析转 ...