poj 3683(2-SAT+SCC)
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)的更多相关文章
- 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 / 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 ...
- POJ 3683 Priest John's Busiest Day (2-SAT+输出可行解)
题目地址:POJ 3683 第一次做须要输出可行解的题目. . .大体思路是先用强连通来推断是否有可行解,然后用逆序建图.用拓扑排序来进行染色.然后输出可行解. 详细思路见传送门 由于推断的时候少写了 ...
- 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(2-sat+输出一组可行解)
题目链接:http://poj.org/problem?id=3683 思路:对于每个结婚仪式,只有在开始或结束时进行这两种选择,我们可以定义xi为真当且仅当在开始时进行.于是我们可以通过时间先后确定 ...
- POJ 3683 Priest John's Busiest Day (2-SAT,常规)
题意: 一些人要在同一天进行婚礼,但是牧师只有1个,每一对夫妻都有一个时间范围[s , e]可供牧师选择,且起码要m分钟才主持完毕,但是要么就在 s 就开始,要么就主持到刚好 e 结束.因为人数太多了 ...
- POJ 3683 Priest John's Busiest Day[2-SAT 构造解]
题意: $n$对$couple$举行仪式,有两个时间段可以选择,问是否可以不冲突举行完,并求方案 两个时间段选择对应一真一假,对于有时间段冲突冲突的两人按照$2-SAT$的规则连边(把不冲突的时间段连 ...
- POJ 3683 Priest John's Busiest Day (2-SAT)
Priest John's Busiest Day Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6900 Accept ...
随机推荐
- CMake系列之三:多个源文件-同一目录
同一目录,多个源文件 把前面的main.c里面的power函数单独写入到一个MathFunctions.c源文件里,目录下的文件结构如下: ./Demo2 | +--- main.c | +--- M ...
- scipy的一些函数名
rvs:随机变量pdf:概率密度函数cdf:累计分布函数sf:残存函数(1-CDF)ppf:分位点函数(CDF的逆)isf:逆残存函数(sf的逆)stats:返回均值,方差,(费舍尔)偏态,(费舍尔) ...
- ajax 异步请求
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- PAT 1049 数列的片段和
https://pintia.cn/problem-sets/994805260223102976/problems/994805275792359424 给定一个正数数列,我们可以从中截取任意的连续 ...
- HTML 5 Canvas vs. SVG
pick up from http://www.w3school.com.cn/html5/html_5_canvas_vs_svg.asp Canvas 与 SVG 的比较 下表列出了 canvas ...
- Vue 的语法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Ideal test 不执行main方法了
参考:idea 导入项目后不能执行main方法 用了ideal之后,发现自己的项目里面没有test文件夹,自己建了一个,发现竟然不能执行main函数, 后来经过点播之后,才知道,光建立文件夹是没用的, ...
- C# 网络请求
C#自带网络请求 由于偶尔会用到服务端请求,写下随笔,以便下次使用 . var Url = "http://rueiqiang.vicp.net/api/Franchisee/QueryIn ...
- inf
下确界 inf,表示下确界,英文名infimum. 对于函数y=f(x),在使f(x)大于等于M成立的所有常数M中,我们把M的最大值max(M)(即函数y=f(x)的最小值)叫做函数y=f(x)的下确 ...
- Linux学习之/etc/init.d/目录和rc.local脚本
init.d目录中包含很多系统服务的启动和停止脚本,比较常用的就是网络服务,当你修改了网络配置时,可以自行 sudo /etc/init.d/networking restart 命令来重启网络服务 ...