版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengwill97/article/details/82056098
题意
有一个小镇上只有一个牧师。这个小镇上有一个传说,在九月一日结婚的人会受到爱神的保佑,但是要牧师举办一个仪式。这个仪式要么在婚礼刚刚开始的时候举行,要么举行完婚礼正好结束。
现在已知有n场婚礼,告诉你每一场的开始和结束时间,以及举行仪式所需要的时间。问牧师能否参加所有的婚礼,如果能则输出一种方案。
题解
2-SAT + 路径输出
首先建图不难,判断两个时间段是否相交。
然后按照tarjan缩点,跑一边逆拓扑排序,按照逆序的结果开始选择,并把它的对称点删掉。求出来的就是结果。
逆拓扑排序直接把缩点后的图边反向建立,然后跑一边正的拓扑排序就好了。
注意输出的时候要按照原来婚礼的顺序进行输出。
代码
#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int tot, head[10005], nhead[10005], tot2;
int n;
struct edge{
int to, nxt;
}e[nmax<<1], ng[nmax<<1];
void add_edge(int u, int v) {
e[tot].to = v;
e[tot].nxt = head[u];
head[u] = tot++;
}
void add_edge2(int u, int v) {
ng[tot2].to = v;
ng[tot2].nxt = nhead[u];
nhead[u] = tot2++;
}
struct Node{
int st1, st2, last;
}node[10005];
int dfn[10005], low[10005], ss[10005], st, scc_cnt, color[10005], in[10005], dfs_clock;
int belong[10005], oppcolor[10005];
bool instack[10005], ban[10005];
vector<int> scc[10005];
queue<int> q;
void init() {
tot2 = scc_cnt = st = dfs_clock = tot = 0 ;
while(!q.empty()) q.pop();
memset(head, -1, sizeof head);
memset(nhead, -1, sizeof nhead);
memset(dfn, 0, sizeof dfn);
memset(low, 0, sizeof low);
memset(color, 0, sizeof color);
memset(ban, 0 ,sizeof ban);
memset(belong, 0, sizeof belong);
memset(in, 0, sizeof in);
memset(oppcolor, 0, sizeof oppcolor);
}
void tarjan(int u) {
dfn[u] = low[u] = ++ dfs_clock;
ss[st++] = u;
instack[u] = true;
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(instack[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]) {
scc_cnt++;
scc[scc_cnt].clear();
int tmp;
while(1) {
tmp = ss[--st];
color[tmp] = scc_cnt;
scc[scc_cnt].push_back(tmp);
instack[tmp] = false;
if(tmp == u)
break;
}
}
}
void toposort(int u) {
q.push(u);
in[u] = -1;
for(int i = nhead[u]; i != -1; i = ng[i].nxt) {
int v = ng[i].to;
in[v] --;
if(!in[v])
toposort(v);
}
}
bool notcross(int as, int ae, int bs, int be) {
if(be <= as || bs >= ae)
return true;
else
return false;
}
void dfs(int u) {
ban[u] = 2;
for(int i = nhead[u]; i != -1; i = ng[i].nxt) {
int v = ng[i].to;
if(ban[v] == 0)
dfs(v);
}
}
void show(int hour, int minute) {
if(hour < 10) printf("0%d:",hour);
else printf("%d:",hour);
if(minute < 10) printf("0%d",minute);
else printf("%d",minute);
}
int main(){
while(scanf("%d", &n) != EOF) {
init();
int sth, stm, edh, edm , last;
for(int i = 1; i <= n; ++i) {
scanf("%d", &sth);
getchar();
scanf("%d %d", &stm, &edh);
getchar();
scanf("%d %d", &edm, &last);
node[i].st1 = sth * 60 + stm;
node[i].st2 = edh * 60 + edm - last;
node[i].last = last;
}
for(int i = 1; i <= n; ++i) {
for(int j = i + 1; j <= n; ++j) {
if(!notcross(node[i].st1 , node[i].st1 + node[i].last, node[j].st1, node[j].st1 + node[j].last)) {
add_edge(i, j + n);
add_edge(j, i + n);
}
if(!notcross(node[i].st2 ,node[i].st2 + node[i].last, node[j].st1, node[j].st1 + node[j].last)) {
add_edge(i + n, j + n);
add_edge(j, i);
}
if(!notcross(node[i].st1, node[i].st1 + node[i].last, node[j].st2, node[j].st2 + node[j].last)) {
add_edge(i, j);
add_edge(j + n, i + n);
}
if(!notcross(node[i].st2, node[i].st2 + node[i].last, node[j].st2, node[j].st2+ node[j].last)) {
add_edge(i + n, j);
add_edge(j + n, i);
}
}
}
for(int i = 1; i <= 2* n; ++i) {
if(!dfn[i]) {
tarjan(i);
}
}
bool isok = true;
for(int i = 1; i <= n; ++i) {
if(color[i] == color[i + n]) {
isok = false;
break;
}
}
if(!isok) {
printf("NO\n");
continue;
} else
printf("YES\n");
for(int u = 1; u <= 2 * n; ++u) {
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(color[u] != color[v]) {
add_edge2(color[v], color[u]);
in[color[u]] ++;
}
}
if(u <= n) oppcolor[color[u]] = color[u + n];
else oppcolor[color[u]] = color[u - n];
}
for(int i = 1; i <= scc_cnt; ++i) {
if(!in[i])
toposort(i);
}
for(int j = 1; j <= scc_cnt; ++j){
int now = q.front();
q.pop();
if(ban[now] == 0) {
ban[now] = 1;
ban[oppcolor[now]] = 2;
for(int i = 0; i < scc[now].size(); ++i) {
belong[scc[now][i]] = 1;
}
}
}
for(int i = 1; i <= n; ++i) {
if(belong[i] == 1) {
show(node[i].st1 / 60 , node[i].st1 % 60);
printf(" ");
show( (node[i].st1 + node[i].last) / 60, (node[i].st1 + node[i].last) % 60);
printf("\n");
} else {
show(node[i].st2 / 60 , node[i].st2 % 60);
printf(" ");
show( (node[i].st2 + node[i].last) / 60, (node[i].st2 + node[i].last) % 60);
printf("\n");
}
}
}
return 0;
}