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这段时间.问神父能否出席所有仪式,如 ...
随机推荐
- 从LINQ开始之LINQ to Objects(下)
前言 上一篇<从LINQ开始之LINQ to Objects(上)>主要介绍了LINQ的体系结构.基本语法以及LINQ to Objects中标准查询操作符的使用方法. 本篇则主要讨论LI ...
- [HDU1004] Let the balloon rise - 让气球升起来
Problem Description Contest time again! How excited it is to see balloons floating around. But to te ...
- Windows 修改电脑属性(一)
修改电脑属性里的注册信息 修改电脑属性的注册信息 运行注册表的方法:开始→运行→regedit→确定 1.CPU型号可以注册表编辑器中定位到下面的位置: HKEY_LOCAL_MACHINE\HARD ...
- JavaSE教程-04Java中循环语句for,while,do···while
** Java的循环语句 ** 引入: 生活中有循环,程序的世界也有循环. 思考:生活中有哪些循环的事情? 总结:什么是循环? 重复做类似的事情,而且有终止条件,如果没有终止条件会是怎样? 类似这样的 ...
- Vue 爬坑之路(四)—— 与 Vuex 的第一次接触
在 Vue.js 的项目中,如果项目结构简单, 父子组件之间的数据传递可以使用 props 或者 $emit 等方式 http://www.cnblogs.com/wisewrong/p/62660 ...
- js中的事件,内置对象,正则表达式
[JS中的事件分类] 1.鼠标事件: click/dbclick/mouseover/mouseout/mousemove/mousedown/mouseup 2.键盘事件: keydown: 键盘按 ...
- linux 下tomcat的安装
写在前面: 由于项目使用jdk1.6开发,所以对应服务器应安装jdk1.6和tomcat6 --- 1.环境变量的配置: 打开/etc/bashrc配置环境变量 JAVA_HOME=/usr/apps ...
- maven打包 bat自动化打包
maven打包,首先cd到项目根目录,如果想跳过测试阶段,可用:mvn package -DskipTests bat命令,说明start是打开文件夹的意思:e: cd E:\workspace\it ...
- Linux搭建SVN服务器(服务端)
Linux搭建SVN服务器(服务端) 1 安装SVN SVN客户端:TortoiseSVN,官网下载:https://tortoisesvn.net/downloads.html(客户端) # yum ...
- SmartSql漫谈
最近在看smartSql源码,兄弟写的.写的很不错取取经. 记录下一些学习的东西,刚开始我先不系统的写了,随意一点哈,我看的差不多再给大家一个模块一个模块系统的写. public T ExecuteS ...