Priest John's Busiest Day(2-SAT决策输出)

Priest John's Busiest Day(luogu)

Description

牧师约翰在9月1日这天非常的忙碌。

有 N 对情侣在这天准备结婚,每对情侣都预先计划好了婚礼举办的时间,其中第 i 对情侣的婚礼从时刻 Si 开始,到时刻 Ti 结束。

婚礼有一个必须的仪式:站在牧师面前聆听上帝的祝福。

这个仪式要么在婚礼开始时举行,要么在结束时举行。

第 i 对情侣需要 Di 分钟完成这个仪式,即必须选择 Si~Si+Di 或 Ti−Di~Ti 两个时间段之一。

牧师想知道他能否满足每场婚礼的要求,即给每对情侣安排Si~Si+Di 或 Ti−Di~Ti,使得这些仪式的时间段不重叠。

若能满足,还需要帮牧师求出任意一种具体方案。

注意,约翰不能同时主持两场婚礼。

如果一场仪式的结束时间与另一场仪式的开始时间相同,则不算重叠。

例如:一场仪式安排在08:00~09:00,另一场仪式安排在09:00~10:00,则不认为两场仪式出现重叠。

输入格式

第一行包含整数N。

接下来N行,每行包含 Si,Ti,D,其中 S和 Ti 是 h:m 形式。

输出格式

第一行输出能否满足,能则输出”YES”,否则输出”NO”。

接下来N行,每行给出一个具体时间段安排。

数据范围

1N1000

Solution

每对新人有两个选择和时间之间的约束关系使我们容易想到用2-SAT做。

先将小时换算成分钟(注意T1是秒)方便后续计算

将时间有冲突的新人之间连有向边。(详见代码)

此题关键在于输出安排

我们知道强联通缩点后按照编号从大到小即为拓扑序从小到大

而拓扑序大的点一定没有路径到拓扑序小的点

即当有合法方案时,对于每对新人,采取拓扑序大的点对应的选择

Code

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
const int N=2e3+10,M=4e6+10;
int n,s[N][2],t[N][2],s_h,s_m,t_h,t_m,a,b,c;
int head[N],nxt[M],to[M],cnt,d[N],opp[N];
int dfn[N],low[N],tot,st[N],top,scc;
bool in[N];
struct node
{
    int st,ed;
    bool operator <(const node &o)const
    {
        return st<o.st;
    }
};
vector <node> ans;
void add(int x,int y)
{
    to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++tot;
    st[++top]=u,in[u]=true;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(!dfn[v]) tarjan(v),low[u]=min(low[v],low[u]);
        else if(in[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        int z;
        scc++;
        do{
            z=st[top--];
            in[z]=false,d[z]=scc;
        }while(z!=u);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d:%d %d:%d %d",&s_h,&s_m,&t_h,&t_m,&c);
        a=s_h*60+s_m,b=t_h*60+t_m;
        s[i][0]=a,t[i][0]=a+c,s[i][1]=b-c,t[i][1]=b;
    }
    for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++)
        for(int p=0;p<2;p++) for(int q=0;q<2;q++)
            if(!(t[i][p]<=s[j][q] || t[j][q]<=s[i][p]))
                add(i+n*p,j+n*(1-q)),add(j+n*q,i+n*(1-p));
    for(int i=1;i<=n*2;i++)
        if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++)
    {
        if(d[i]==d[i+n])
        {
            puts("NO");
            return 0;
        }
        opp[i]=i+n,opp[i+n]=i;
    }
    puts("YES");
    for(int i=1;i<=n;i++)
        ans.push_back((node){s[i][d[i]>d[opp[i]]],t[i][d[i]>d[opp[i]]]});
    sort(ans.begin(),ans.end());
    for(int i=0;i<n;i++)
    {
        node tp=ans[i];
        s_h=tp.st/60,s_m=tp.st%60;
        t_h=tp.ed/60,t_m=tp.ed%60;
        printf("%02d:%02d %02d:%02d\n",s_h,s_m,t_h,t_m);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hsez-cyx/p/12348517.html