传送门: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. 查看服务器系统资源(cpu,内容)利用率前几位的进程的方法

    在日常运维工作中,我们经常需要了解服务器上的系统资源的使用情况,要清楚知道一些重要进程所占的资源比例.这就需要熟练掌握下面几个命令的使用: 1)查看占用CPU最高的5个进程 # ps aux | so ...

  2. C++中struct 和 class的区别

    首先,C++中类的定义,从狭义上理解,就是我们使用的class类型.从广义上,类就是定义了一个新的类型和新的作用域,它具有成员函数和成员数据. 而对广义类定义的实现分为两种,一种是使用struct实现 ...

  3. Windows命令行下如何使用批处理异步打开一个浏览器进程

    Browse.bat @echo off if '%1'=='-c' ( start /d "C:\Program Files\Google\Chrome\Application\" ...

  4. phpstorm 注释模板

    /** * Created by ${PRODUCT_NAME}. * User: ${USER} * Date: ${DATE} * Time: ${TIME} */

  5. Postgresql 密码设置

    今天下午 陷进去了 其实很简单的一个事情结果浪费了 接近一个小时. 做事情必须要细致一些. 自己的确做的不好. 这里面简单说一下pg_hba.conf 和 postgresql 密码的一些设置问题. ...

  6. carson常用linux命令整理

    注:通过日常所用到的一些命令进行整理添加!! 完整的命令可参考:Linux命令大全 1.cp命令 cp命令用来将一个或多个源文件或者目录复制到指定的目的文件或目录. 2.mount(挂载)命令 在li ...

  7. C++ 动态内存分配(6种情况,好几个例子)

    1.堆内存分配 : C/C++定义了4个内存区间: 代码区,全局变量与静态变量区,局部变量区即栈区,动态存储区,即堆(heap)区或自由存储区(free store). 堆的概念: 通常定义变量(或对 ...

  8. Java之byte、char和String类型相互转换

    package basictype; /** * byte.char和String类型相互转换 */ public class CHJavaType { public static void main ...

  9. ubuntu 安装 postgresql

    安装环境: Ubuntu 10.04-desktop-i386 PostgreSQL 8.4 1. 安装PostgreSQL 输入如下命令 sudo apt-get install postgresq ...

  10. poj2115-C Looooops -线性同余方程

    线性同余方程的模板题.和青蛙的约会一样. #include <cstdio> #include <cstring> #define LL long long using nam ...