题目大意:
注释代码:
/*
* Problem ID : POJ 3683 Priest John's Busiest Day
* Author : Lirx.t.Una
* Language : C++
* Run Time : 266 ms
* Run Memory : 23832 KB
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack>
//思路:
//如果x表示第x号婚礼在开始时举行而-x表示在结束时举行
//比如x∧y就表示婚礼x和y都在开始时举行
//但是如果从题给的事实中得出x∧y不成立(即两场婚礼会有冲突)
//则不冲突的情况只可能发生在-(x∧y)中了,如果该表达式也无法成立的话则牧师就不能完成任务了
//由此可见算法的步骤为:
//1:找出所有使i∧j不成立的(i, j)对子,其中i、j为布尔文字,i、j可以为x也可以为-x
//2:然后将i∧j化为-i∨-j形式(为了构造主合取范式),最后便是求布尔方程(a1∨b1)∧(a2∨b2)...(an^bn) = true
//3:对于每个布尔子句i∨j,可以化为蕴含表达式-i->j ∧ -j->i,这样主合取范式就全部化为蕴含式的∧
//4:对i和-i进行编号,然后对于每一对i->j做一条有向边构图进行强连通分量分解
//5:如果存在i和-i在同一个强连通分量中则布尔方程无解,否则就有解
//6:对于有解的情况,如果要求某个布尔变量x的取值
//如果x所在的强连通分量在缩点图中的拓扑排序在-x之后的强连通分量之后就去true否则就取false
//婚礼的最大数量
#define MAXN 1000
#define MAXNN 2000
using namespace std;
short s[MAXN + 1];//婚礼开始时间
short t[MAXN + 1];//截止时间
short d[MAXN + 1];//祈祷用时
//正向图和反向图
//其中某个点i表示i号婚礼在开始时进行,则i + n表示在i在截止时进行两种布尔状态
//其中n为婚礼数量
int head[MAXNN + 1];
int to[MAXNN * MAXNN + 1];
int nxt[MAXNN * MAXNN + 1];
int _head[MAXNN + 1];
int _to[MAXNN * MAXNN + 1];
int _nxt[MAXNN * MAXNN + 1];
int e;
short blg[MAXNN + 1];
bool vis[MAXNN + 1];
int nb;
stack<short> stk;
inline int
min( int a, int b ) {
return a < b ? a : b;
}
inline int
max( int a, int b ) {
return a > b ? a : b;
}
inline void
addarc( int u, int v ) {
to[e] = v;
nxt[e] = head[u];
head[u] = e;
_to[e] = u;
_nxt[e] = _head[v];
_head[v] = e++;
}
void
dfs(int u) {
int v, i;
vis[u] = true;
for ( i = head[u]; i; i = nxt[i] )
if ( !vis[ v = to[i] ] )
dfs(v);
stk.push(u);
}
void
_dfs(int u) {
int v, i;
vis[u] = true;
blg[u] = nb;
for ( i = _head[u]; i; i = _nxt[i] )
if ( !vis[ v = _to[i] ] )
_dfs(v);
}
void
kosa(int nn) {
int i;
for ( i = 1; i <= nn; i++ )
if ( !vis[i] )
dfs(i);
memset(vis, 0, sizeof(vis));
for ( nb = 0; !stk.empty(); stk.pop() )
if ( !vis[ i = stk.top() ] )
++nb, _dfs(i);
}
int
main() {
int n, nn;//婚礼数和布尔状态数
int hh, mm, dd;//临时接受小时、分钟、用时
int i, j;
int tmp;
scanf("%d", &n);
nn = n << 1;
e = 1;
for ( i = 1; i <= n; i++ ) {
scanf("%d:%d", &hh, &mm);
s[i] = hh * 60 + mm;//将时间转化为以分钟为单位
scanf("%d:%d", &hh, &mm);
t[i] = hh * 60 + mm;
scanf("%d", &dd);
d[i] = dd;
}
for ( i = 1; i <= n; i++ )
for ( j = i + 1; j <= n; j++ ) {//找出所有^表达式不成立的对子
//i∧j ≡ -i∨-j ≡ i->-j∧j->-i
if ( min( s[i] + d[i], s[j] + d[j] ) > max( s[i], s[j] ) ) {//都在开始时冲突
addarc( i, j + n );
addarc( j, i + n );
}
//i∧-j ≡ -i∨j ≡ i->j∧-j->-i
if ( min( s[i] + d[i], t[j] ) > max( s[i], t[j] - d[j] ) ) {//开始和截止冲突
addarc( i, j );
addarc( j + n, i + n );
}
//-i∧j ≡ i∨-j ≡ -i->-j∧j->i
if ( min( t[i], s[j] + d[j] ) > max( t[i] - d[i], s[j] ) ) {//截止和开始冲突
addarc( i + n, j + n );
addarc( j, i );
}
//-i∧-j ≡ i∨j ≡ -i->j∧-j->i
if ( min( t[i], t[j] ) > max( t[i] - d[i], t[j] - d[j] ) ) {//都在截止时冲突
addarc( i + n, j );
addarc( j + n, i );
}
}
kosa(nn);
for ( i = 1; i <= n; i++ )
if ( blg[i] == blg[i + n] ) {//自己和自己的非在同一个SCC中则布尔方程误解
puts("NO");
return 0;
}
puts("YES");
for ( i = 1; i <= n; i++ )
if ( blg[i] > blg[i + n] ) {//自己比自己的非的强连通分量的拓扑排序序号要大则取true(就表示在开始时举办)
tmp = s[i] + d[i];
printf("%02d:%02d %02d:%02d\n",
s[i] / 60, s[i] % 60,
tmp / 60, tmp % 60);
}
else {//否则就false的情况(在截止时举办)
tmp = t[i] - d[i];
printf("%02d:%02d %02d:%02d\n",
tmp / 60, tmp % 60,
t[i] / 60, t[i] % 60);
}
return 0;
}
无注释代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack>
#define MAXN 1000
#define MAXNN 2000
using namespace std;
short s[MAXN + 1];
short t[MAXN + 1];
short d[MAXN + 1];
int head[MAXNN + 1];
int to[MAXNN * MAXNN + 1];
int nxt[MAXNN * MAXNN + 1];
int _head[MAXNN + 1];
int _to[MAXNN * MAXNN + 1];
int _nxt[MAXNN * MAXNN + 1];
int e;
short blg[MAXNN + 1];
bool vis[MAXNN + 1];
int nb;
stack<short> stk;
inline int
min( int a, int b ) {
return a < b ? a : b;
}
inline int
max( int a, int b ) {
return a > b ? a : b;
}
inline void
addarc( int u, int v ) {
to[e] = v;
nxt[e] = head[u];
head[u] = e;
_to[e] = u;
_nxt[e] = _head[v];
_head[v] = e++;
}
void
dfs(int u) {
int v, i;
vis[u] = true;
for ( i = head[u]; i; i = nxt[i] )
if ( !vis[ v = to[i] ] )
dfs(v);
stk.push(u);
}
void
_dfs(int u) {
int v, i;
vis[u] = true;
blg[u] = nb;
for ( i = _head[u]; i; i = _nxt[i] )
if ( !vis[ v = _to[i] ] )
_dfs(v);
}
void
kosa(int nn) {
int i;
for ( i = 1; i <= nn; i++ )
if ( !vis[i] )
dfs(i);
memset(vis, 0, sizeof(vis));
for ( nb = 0; !stk.empty(); stk.pop() )
if ( !vis[ i = stk.top() ] )
++nb, _dfs(i);
}
int
main() {
int n, nn;
int hh, mm, dd;
int i, j;
int tmp;
scanf("%d", &n);
nn = n << 1;
e = 1;
for ( i = 1; i <= n; i++ ) {
scanf("%d:%d", &hh, &mm);
s[i] = hh * 60 + mm;
scanf("%d:%d", &hh, &mm);
t[i] = hh * 60 + mm;
scanf("%d", &dd);
d[i] = dd;
}
for ( i = 1; i <= n; i++ )
for ( j = i + 1; j <= n; j++ ) {
if ( min( s[i] + d[i], s[j] + d[j] ) > max( s[i], s[j] ) ) {
addarc( i, j + n );
addarc( j, i + n );
}
if ( min( s[i] + d[i], t[j] ) > max( s[i], t[j] - d[j] ) ) {
addarc( i, j );
addarc( j + n, i + n );
}
if ( min( t[i], s[j] + d[j] ) > max( t[i] - d[i], s[j] ) ) {
addarc( i + n, j + n );
addarc( j, i );
}
if ( min( t[i], t[j] ) > max( t[i] - d[i], t[j] - d[j] ) ) {
addarc( i + n, j );
addarc( j + n, i );
}
}
kosa(nn);
for ( i = 1; i <= n; i++ )
if ( blg[i] == blg[i + n] ) {
puts("NO");
return 0;
}
puts("YES");
for ( i = 1; i <= n; i++ )
if ( blg[i] > blg[i + n] ) {
tmp = s[i] + d[i];
printf("%02d:%02d %02d:%02d\n",
s[i] / 60, s[i] % 60,
tmp / 60, tmp % 60);
}
else {
tmp = t[i] - d[i];
printf("%02d:%02d %02d:%02d\n",
tmp / 60, tmp % 60,
t[i] / 60, t[i] % 60);
}
return 0;
}