牧师约翰最忙碌的一天 2-SAT

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <array>

typedef long long ll;
using namespace std;

const int N = 4010;

vector<int> e[N];
vector<array<ll, 4>> q;
int n, dfn[N], low[N], stk[N], instk[N], scc, tot, top, id[N];

bool check(ll sta1, ll end1, ll sta2, ll end2)
{
    return end1 > sta2 && end2 > sta1; //  相交
}

void tarjan(int u)
{
    dfn[u] = low[u] = ++ tot;
    stk[ ++ top] = u, instk[u] = true;
    
    for (auto v : e[u])
    {
        if (!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (instk[v])
            low[u] = min(low[u], dfn[v]);
    }
    
    if (dfn[u] == low[u])
    {
        ++ scc;
        int y;
        do {
            y = stk[top -- ];
            instk[y] = false;
            id[y] = scc;
        } while (y != u);
    }
}


int main()
{
    scanf("%d", &n);
    for (int i = 0;i < n;i ++ )
    {
        ll a, b, c, d, t;
        scanf("%lld:%lld %lld:%lld %lld", &a, &b, &c, &d, &t);
        ll l = a * 60 + b, r = c * 60 + d;
        q.push_back({l, r, t, b});
    }
    for (int i = 0;i < n;i ++ )
    for (int j = 0;j < n;j ++ )
    {
        if (i == j) continue;
        int a = i * 2, b = j * 2;
        // x ^ 1 表示 尾
        // head and head
        if (check(q[i][0], q[i][0] + q[i][2], q[j][0], q[j][0] + q[j][2]) )
        {
            e[a].push_back(b ^ 1); // 
            e[b].push_back(a ^ 1);
        }
        // head and trail
        if (check(q[i][0], q[i][0] + q[i][2], q[j][1] - q[j][2], q[j][1]))
        {
            e[a].push_back(b);
            e[b ^ 1].push_back(a ^ 1);
        }
        // trail and head 
        if (check(q[i][1] - q[i][2], q[i][1], q[j][0], q[j][0] + q[j][2]))
        {
            e[a ^ 1].push_back(b ^ 1);
            e[b].push_back(a);
        }
        // trail and treil
        if (check(q[i][1] - q[i][2], q[i][1], q[j][1] - q[j][2], q[j][1]))
        {
            e[a ^ 1].push_back(b);
            e[b ^ 1].push_back(a);
        }
    }
    
    for (int i = 0;i < 2 * n;i ++ ) if (!dfn[i]) tarjan(i);
    
    for (int i = 0;i < n;i ++ )
        if (id[i * 2] == id[i * 2 + 1]){
            puts("NO");
            exit(0);
        }
    puts("YES");
    for (int i = 0;i < n;i ++ )
    {
        if (id[i * 2] < id[i * 2 + 1])
            printf("%02lld:%02lld %02lld:%02lld\n", 
                    q[i][0] / 60, q[i][0] % 60, (q[i][0] + q[i][2]) / 60, (q[i][0] + q[i][2]) % 60);
        else 
            printf("%02lld:%02lld %02lld:%02lld\n", 
                    (q[i][1] - q[i][2]) / 60, (q[i][1] - q[i][2]) % 60, 
                    q[i][1] / 60, q[i][1] % 60);
            
            
    }
}

~~~~~~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

璀璨的秋叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值