题意:有N个婚礼,每个婚礼可以在两段时间内举行,要求N段婚礼的时间没有相交,可行则输出方案
分析:2-SAT求解.建图就是若婚礼i的第一段时间与婚礼j的第一段时间相交则选i1则必选j2,以此类推.
Tarjan跑出强联通分量之后,反向缩点建边并染色,最后输出可行解
2-SAT输出方案可作为模板,其思路参考博客:https://blog.csdn.net/Hawo11/article/details/74908233
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
const int MAXM = 2e6+5;
struct Edge{
int v,next;
}edges[MAXM],E[MAXM];
int head[maxn],tot;
int H[maxn],tt;
stack<int> S;
int pre[maxn],low[maxn],sccno[maxn],dfn,scc_cnt,ind[maxn],col[maxn];
void init()
{
tt = tot = dfn = scc_cnt=0;
memset(H,-1,sizeof(H));
memset(pre,0,sizeof(pre));
memset(sccno,0,sizeof(sccno));
memset(head,-1,sizeof(head));
memset(ind,0,sizeof(ind));
}
void AddEdge(int u,int v) {
edges[tot] = (Edge){v,head[u]};
head[u] = tot++;
}
void nAddEdge(int u,int v){
E[tt] = (Edge){v,H[u]};
H[u] = tt++;
}
void Tarjan(int u)
{
int v;
pre[u]=low[u]=++dfn;
S.push(u);
for(int i=head[u];~i;i=edges[i].next){
v= edges[i].v;
if(!pre[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!sccno[v]){
low[u]=min(low[u],pre[v]);
}
}
if(pre[u]==low[u]){
int x;
++scc_cnt;
for(;;){
x = S.top();S.pop();
sccno[x]=scc_cnt;
if(x==u)break;
}
}
}
int con[maxn];
struct Node{
int st,ed;
}p[2005];
int N,all;
#include<queue>
void solve()
{
int a,b;
for(int i=0;i<all;++i){
if(!pre[i]) Tarjan(i);
}
for(int i=0;i<all;i+=2){
if(sccno[i]==sccno[i^1]){
printf("NO
");
return;
}
a = sccno[i], b = sccno[i^1];
con[a] = b;
con[b] = a;
}
printf("YES
");
//缩点
for(int u=0;u<all;++u){
a = sccno[u];
for(int i = head[u];~i;i=edges[i].next){
int v = edges[i].v;
b = sccno[v];
if(a!=b){
nAddEdge(b,a);
ind[a]++;
}
}
}
//逆拓扑排xu
queue<int> Q;
memset(col,0,sizeof(col));
for(int i=1;i<=scc_cnt;++i){
if(!ind[i]) Q.push(i);
}
while(!Q.empty()){
int u =Q.front(); Q.pop();
if(!col[u]){
col[u] = 1;
col[con[u]] = 2;
}
for(int i=H[u];~i;i=E[i].next){
int v = E[i].v;
ind[v]--;
if(!ind[v]){
Q.push(v);
}
}
}
int h1,m1,h2,m2;
for(int i=0;i<all;i+=2){
int pt;
if(col[sccno[i]]== 1) pt = i;
else pt = i^1;
h1 = p[pt].st/60,m1 =p[pt].st %60;
h2 = p[pt].ed/60,m2 =p[pt].ed %60;
printf("%02d:%02d %02d:%02d
",h1,m1,h2,m2);
}
}
bool check(int i,int j)
{
if(p[i].ed<=p[j].st || p[j].ed<=p[i].st) return true;
else return false;
}
char op[50];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int h1,m1,h2,m2,len;
while(scanf("%d",&N)==1){
init();
all = 2*N;
bool flag = true;
for(int i=0;i<all;i+=2){
scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&len);
p[i].st = h1*60+m1;
p[i].ed = p[i].st + len;
p[i^1].st = h2*60+m2-len;
p[i^1].ed = p[i^1].st +len;
if(p[i^1].ed - p[i].st<len) flag = false;
}
if(!flag){
printf("NO
");
continue;
}
int a1,a2,b1,b2;
//[1-2N] 为去 ,[2N+1,4N]为不去
for(int i=0;i<all;i+=2){
a1 = i; a2 = i^1;
for(int j= i+2 ;j< all ; j+=2){
b1 = j, b2 =j^1;
if(!check(a1,b1)){
AddEdge(a1,b2);
AddEdge(b1,a2);
}
if(!check(a1,b2)){
AddEdge(a1,b1);
AddEdge(b2,a2);
}
if(!check(a2,b1)){
AddEdge(a2,b2);
AddEdge(b1,a1);
}
if(!check(a2,b2)){
AddEdge(a2,b1);
AddEdge(b2,a1);
}
}
}
solve();
}
return 0;
}