传送门:Problem 3683

https://www.cnblogs.com/violet-acmer/p/9769406.html

参考资料:

  [1]:挑战程序设计竞赛

题意:

  有n场婚礼,每场婚礼有起始时间si,结束时间ti,还有一个主持仪式需要花费ti时间,ti必须安排在婚礼的开始或者结束。

  主持由神父来做,但是只有一个神父,所以各个婚礼的主持时间不能重复,不过神父可以在出席完一个主持仪式后,立刻出席另一个开始时间与其结束时间相等的主持仪式,问你有没有可能正常的安排主持时间,不能输出no,能的话要输出具体的答案:即每个婚礼的主持时间在那个时间段。

题解:

  对于每个结婚仪式 i ,只有在开始或结束时进行主持仪式,两种选择,因此可定义变量 Xi;

      Xi 为真 <=> 在开始时进行主持仪式

  这样,对于婚礼 i 和 j ,如果Si~Si+Di 和 Sj~Sj+Dj 冲突,就有子句 (非Xi V 非Xj) 为真,对于开始和开始,开始和结束,结束和开始,结束和结束分别对应四条子句,也可得到类似的条件。

  于是,要保证所有主持仪式的时间不冲突,只要考虑将这些所有的子句用 ^(合取)连接起来所得道德布尔公式就好了。

  例如,对于输入的样例可以得到的布尔公式为:

                                            

  而当x1为真而x2为假时,其值为真。

  这样,我们就把原问题转为了2-SAT问题,接下来只要进行强连通分量分解并判断是否有使得布尔公式值为真的一组布尔变量就好了。

  以上分析来自挑战程序设计竞赛P326。

难点:  

  根据2-SAT建立有向图,用SCC分解强连通分量

AC代码:

 #include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
#define mem(a,b) (memset(a,b,sizeof a))
#define pb push_back
const int maxn=1e3+; //X1~Xn : 1~n
//非X1~非Xn : n+1~2*n
int n;
int s[maxn];
int t[maxn];
int d[maxn];
vector<int >G[*maxn],rG[*maxn];//注意此处是 2*maxn
vector<int >vs;
int scc[*maxn];
bool vis[*maxn];
void addEdge(int u,int v)
{
G[u].pb(v);
rG[v].pb(u);
}
void SAT()
{
for(int i=;i <= n;++i)
{
for(int j=;j < i;++j)
{
if(max(s[i],s[j]) < min(s[j]+d[j],s[i]+d[i]))//第 i 场婚礼的开始时主持时间与第 j 场婚礼的开始时主持时间冲突
addEdge(i,j+n),addEdge(j,i+n);
if(max(s[i],t[j]-d[j]) < min(t[j],s[i]+d[i]))//第 i 场婚礼的开始时主持时间与第 j 场婚礼的结束时主持时间冲突
addEdge(i,j),addEdge(j+n,i+n);//注意,第二处是 j+n -> i+n
if(max(s[j],t[i]-d[i]) < min(t[i],s[j]+d[j]))//第 i 场婚礼的结束时主持时间与第 j 场婚礼的开始时主持时间冲突
addEdge(i,j),addEdge(i+n,j+n);//注意,第二处是 i+n -> j+n
if(max(t[i]-d[i],t[j]-d[j]) < min(t[i],t[j]))//第 i 场婚礼的结束时主持时间与第 j 场婚礼的结束时主持时间冲突
addEdge(i+n,j),addEdge(j+n,i);
}
}
}
void Dfs(int u)
{
vis[u]=true;
for(int i=;i < G[u].size();++i)
if(!vis[G[u][i]])
Dfs(G[u][i]);
vs.pb(u);
}
void rDfs(int u,int k)
{
vis[u]=true;
scc[u]=k;
for(int i=;i < rG[u].size();++i)
{
int to=rG[u][i];
if(!vis[to])
rDfs(to,k);
}
}
void SCC()
{
mem(vis,false);
vs.clear();
for(int i=;i <= n;++i)
if(!vis[i])
Dfs(i);
mem(vis,false);
int k=;
for(int i=vs.size()-;i >= ;--i)
if(!vis[vs[i]])
rDfs(vs[i],++k);
}
void Init()
{
for(int i=;i < maxn;++i)
G[i].clear(),rG[i].clear();
}
int main()
{ while(~scanf("%d",&n))
{
Init();
for(int i=;i <= n;++i)
{
int h,m;
char ch;
scanf("%d%c%d",&h,&ch,&m);
s[i]=h*+m;//将开始时间转化为分钟
scanf("%d%c%d",&h,&ch,&m);
t[i]=h*+m;//将结束时间转化为分钟
scanf("%d",d+i);
}
SAT();//根据2-SAT建图
SCC();//强连通分量分解
bool flag=false;
for(int i=;i <= n;++i)
if(scc[i] == scc[i+n])
flag=true;
if(flag)
printf("NO\n");
else
{
printf("YES\n");
for(int i=;i <= n;++i)
{
if(scc[i] > scc[i+n])
printf("%02d:%02d %02d:%02d\n",s[i]/,s[i]%,(s[i]+d[i])/,(s[i]+d[i])%);
else
printf("%02d:%02d %02d:%02d\n",(t[i]-d[i])/,(t[i]-d[i])%,t[i]/,t[i]%);
}
}
}
return ;
}

poj 3683(2-SAT+SCC)的更多相关文章

  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 / 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问题) Descripti ...

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

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

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

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

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

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

  6. poj 3683(2-sat+输出一组可行解)

    题目链接:http://poj.org/problem?id=3683 思路:对于每个结婚仪式,只有在开始或结束时进行这两种选择,我们可以定义xi为真当且仅当在开始时进行.于是我们可以通过时间先后确定 ...

  7. POJ 3683 Priest John's Busiest Day (2-SAT,常规)

    题意: 一些人要在同一天进行婚礼,但是牧师只有1个,每一对夫妻都有一个时间范围[s , e]可供牧师选择,且起码要m分钟才主持完毕,但是要么就在 s 就开始,要么就主持到刚好 e 结束.因为人数太多了 ...

  8. POJ 3683 Priest John's Busiest Day[2-SAT 构造解]

    题意: $n$对$couple$举行仪式,有两个时间段可以选择,问是否可以不冲突举行完,并求方案 两个时间段选择对应一真一假,对于有时间段冲突冲突的两人按照$2-SAT$的规则连边(把不冲突的时间段连 ...

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

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

随机推荐

  1. 浅谈meta viewport设置移动端自适应

    1.viewport 移动设备上的viewport是设备屏幕上用来显示网页的那部分区域,再具体一点就是浏览器上用来显示网页的那部分区域,但viewport又不局限于浏览器可视区域的大小,它可能比浏览器 ...

  2. Visual Studio 2013编辑器+SourceTree代码管理工具及扩展工具

    Visual Studio 2013: 美国微软公司的编辑开发工具 扩展工具: Resharper:进行深度代码分析,函数深度查询(ctrl+鼠标左): Grunt:是基于Node.js的项目以自动化 ...

  3. C. Ehab and a 2-operation task

    链接 [https://codeforces.com/contest/1088/problem/C] 题意 n个数,最多n+1操作,要么前i个数加x,要么前i个数对x取余,最后使得严格递增 分析 直接 ...

  4. C. Make It Equal

    链接 [http://codeforces.com/contest/1065/problem/C] 题意 给你n个高度hi的塔,让你把高的部分切掉,使得最后所有塔一样高,而且每次切的高度之和不大于k ...

  5. 附加题(一)——interesting的抄袭现象

    这次的作业很有意思,是让我们搜索抄袭的同学的个人总结,并让我们列出链接,时间,作者及原因.其实我不是很能理解,抄袭现象是可耻的不受推崇的这是无可厚非,但是为什么要求我们大部分没有抄袭的同学去探究抄袭同 ...

  6. 撰写POPUSH需求文档

    不当家不知柴米贵,撰写了正规的软件需求文档才知道软件工程的复杂性 感谢@洪宇@王需@江林楠下午的加班加点,五个人正闷在406B奋斗中,加油!

  7. VIM编辑器常用命令(转)

    转自:https://www.cnblogs.com/Nice-Boy/p/6124177.html

  8. HDOJ2009_求数列的和

    简单的考察对浮点数使用的水题 HDOJ2009_求数列的和 #include<iostream> #include<stdio.h> #include<stdlib.h& ...

  9. 一个简单的Oracle和 SQLSERVER 重建所有表索引的办法

    1. SQLSERVER 使用微软自带的存储过程 exec sp_msforeachtable 'DBCC DBREINDEX(''?'')' 2. Oracle的办法: select 'alter ...

  10. 小程序的wx.onAccelerometerChange

    https://www.2cto.com/kf/201802/724174.html(copy) 也许有人会问,小程序中都是竖直app形态,要横竖屏判断有什么用?即使判断出了横屏状态,你能把小程序横过 ...