传送门: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. QQ使用的使用评价

    1:界面以及功能:打开软件之后探出登录窗口,基本功能的登录,找回密码,注册帐号等功能均在比较醒目的位置,界面较为友好. 将注册帐号放在打开软件的第一界面当然是正确的选择,给予用户非常直观的提示(没有帐 ...

  2. 复审Partner

    复审代码后,发现了一些问题: 首先说优点:代码十分工整,很清晰,各种类易于理解,逻辑上很通顺. 基本实现了代码功能,输出正确. 发现的缺点:对于文件后缀的识别有点问题,不能识别所需求的所有文件,只有一 ...

  3. oracle加注释

    COMMENT ON table GC_G_DOC84 IS '行政处罚撤销决定书'; COMMENT ON column GC_G_DOC84.CASEID IS '案件记录ID';

  4. QT 窗口置顶功能

    Qt中,保持窗口置顶的设置为: Qt::WindowFlags m_flags = windowFlags(); setWindowFlags(m_flags | Qt::WindowStaysOnT ...

  5. NSLog debug时打印 release时不打印

    创建.h文件,添加以下代码 #ifdef  DEBUG #define NSLog(...)  NSLog(__VA_ARGS__) #else #define NSLog(...)  {} #end ...

  6. vue容易混淆的点小记

    computed.methods及watch函数的差异 computed:基于依赖进行缓存,若依赖不变,则直接调用缓存(适用于性能开销比较大的时候) methods: 不管数据是否变更,都会进行计算( ...

  7. vue的自定义组件和组件传值

    <div id="app"> <div>{{pmessage}}</div> //父组件 <child :message="pm ...

  8. C#微信扫码支付Demo

    1.打开微信支付开发平台: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1 2.下载SDK Demo: C#版下载

  9. [转载]Linux目录说明

    原作者博客: http://blog.51cto.com/yangrong/1288072 将文字部分转移到自己的目录下便于学习记录 感谢~ 2./目录 目录 描述 / 第一层次结构的根.整个文件系统 ...

  10. Jquery 事件冒泡、元素的默认行为的阻止、获取事件类型、触发事件

    $(function(){// 事件冒泡 $('').bind("click",function(event){ //事件内容 //停止事件冒泡 event.stopPropaga ...