Poj3683:Priest John's Busiest Day

题意

n对夫妻要结婚,第i对夫妻结婚的婚礼持续时间为[Si, Ti],他们会举行一个仪式,仪式时间为Di,这个仪式只能举行在开头或者结尾举行,要么[Si, Si+Di],要么[Ti-Di, Ti],然而举行仪式的牧师只有一个,问牧师能否举行完所有仪式
按输入顺序输出方案
手动翻译

Sol

\(2-SAT\)输出一组可行解
这个很烦
\(Tarjan\)缩点成\(DAG\)后再拓扑排序+染色
只传递不选的标记

# include <iostream>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <math.h>
# include <algorithm>
# include <queue>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(2005);
const int __(2e6 + 5);

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, first[_], head[_], cnt, num, s[_], t[_], d[_], cho[_];
int S[_], vis[_], dfn[_], low[_], Index, col[_], deg[_], oth[_];
struct Edge{
    int to, next;
} edge[__], dag[__];
queue <int> Q;

IL void Add(RG int u, RG int v){
    edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
}

IL void Add_DAG(RG int u, RG int v){
    dag[cnt] = (Edge){v, head[u]}, head[u] = cnt++, ++deg[v];
}

IL void Tarjan(RG int u){
    vis[u] = 1, dfn[u] = low[u] = ++Index, S[++S[0]] = u;
    for(RG int e = first[u]; e != -1; e = edge[e].next){
        RG int v = edge[e].to;
        if(!dfn[v]) Tarjan(v), low[u] = min(low[u], low[v]);
        else if(vis[v]) low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] != low[u]) return;
    RG int v = S[S[0]--]; col[v] = ++num, vis[v] = 0;
    while(v != u) v = S[S[0]--], col[v] = num, vis[v] = 0;
}

IL void Dfs(RG int u){
    if(cho[u] != -1) return;
    cho[u] = 0;
    for(RG int e = head[u]; e != -1; e = dag[e].next) Dfs(dag[e].to);
}

IL int GetTime(){
    return Input() * 60 + Input();
}

IL void OutTime(RG int x){
    printf("%.2d:%.2d ", x / 60, x % 60);
}

IL int Cross(RG int l1, RG int r1, RG int l2, RG int r2){
    if(l1 > l2) swap(l1, l2), swap(r1, r2);
    return r1 > l2;
}

int main(RG int argc, RG char* argv[]){
    n = Input(), Fill(first, -1), Fill(head, -1), Fill(cho, -1);
    for(RG int i = 1; i <= n; ++i)
        s[i] = GetTime(), t[i] = GetTime(), d[i] = Input();
    for(RG int i = 1; i < n; ++i)
        for(RG int j = i + 1; j <= n; ++j){
            if(Cross(s[i], s[i] + d[i], s[j], s[j] + d[j])) Add(i, j + n), Add(j, i + n);
            if(Cross(s[i], s[i] + d[i], t[j] - d[j], t[j])) Add(i, j), Add(j + n, i + n);
            if(Cross(t[i] - d[i], t[i], s[j], s[j] + d[j])) Add(i + n, j + n), Add(j, i);
            if(Cross(t[i] - d[i], t[i], t[j] - d[j], t[j])) Add(i + n, j), Add(j + n, i);
        }
    RG int tmp = n << 1; cnt = 0;
    for(RG int i = 1; i <= tmp; ++i) if(!dfn[i]) Tarjan(i);
    for(RG int i = 1; i <= n; ++i){
        if(col[i] == col[i + n]) return puts("NO"), 0;
        oth[col[i]] = col[i + n], oth[col[i + n]] = col[i];
    }
    puts("YES");
    for(RG int i = 1; i <= tmp; ++i)
        for(RG int e = first[i]; e != -1; e = edge[e].next)
            if(col[i] != col[edge[e].to]) Add_DAG(col[edge[e].to], col[i]);
    for(RG int i = 1; i <= num; ++i) if(!deg[i]) Q.push(i);
    while(!Q.empty()){
        RG int u = Q.front(); Q.pop();
        if(cho[u] != -1) continue;
        cho[u] = 1, Dfs(oth[u]);
        for(RG int e = head[u]; e != -1; e = dag[e].next)
            if(!--deg[dag[e].to]) Q.push(dag[e].to);
    }
    for(RG int i = 1; i <= n; ++i){
        if(cho[col[i]]) OutTime(s[i]), OutTime(s[i] + d[i]);
        else OutTime(t[i] - d[i]), OutTime(t[i]);
        puts("");
    }
    return 0;
}

Poj3683:Priest John's Busiest Day

原文地址:https://www.cnblogs.com/cjoieryl/p/8463664.html

时间: 2024-10-26 09:39:41

Poj3683:Priest John's Busiest Day的相关文章

图论(2-sat):Priest John&#39;s Busiest Day

Priest John's Busiest Day Description John is the only priest in his town. September 1st is the John's busiest day in a year because there is an old legend in the town that the couple who get married on that day will be forever blessed by the God of

POJ-3683 Priest John&#39;s Busiest Day

图论中的2-SAT.模板题. #include <cstdio> #include <cstdlib> #include <algorithm> #include <cctype> #include <cstring> #include <iostream> using namespace std; #define rep(i, l, r) for(int i=l; i<=r; i++) #define travel(x) fo

poj3683 Priest John&#39;s Busiest Day

不用topsort的,我也不知道为啥. #include <iostream> #include <cstring> #include <cstdio> using namespace std; struct Node{ int fro, too; }nd[2005]; struct Edge{ int too, nxt, val; }edge[4000005]; int uu, vv, ww, n, hea[2005], cnt, dfn[2005], loo[200

HDU2491 Priest John&#39;s Busiest Day

题目链接 题意: 有n个人要进行乒乓球比赛,每个人都一个能力值,每个人出现的次序就是他们住的位置 现在要求进行一场比赛,三个人,裁判的能力值在两个选手之间,住的位置也在两个人的之间 问这种比赛一共可以进行多少次 思路: 用树状数组做,否则TLE,先从左到右扫一遍,计算每点左边大的个数和小的个数, 再从右到左扫一遍,计算每点右边大和小的个数,然后交叉相乘取和就可以了 代码如下: #include<cstdio> #include<cstring> #include<string

UVA - 1420 Priest John&#39;s Busiest Day

题目大意:有一个司仪,要主持 n 场婚礼,给出婚礼的起始时间和终止时间,每个婚礼需要超过一半的时间做为仪式,并且仪式不能终止.问说司仪能否主持 n 场婚礼. 解题思路:贪心,为了尽量主持多的婚礼,每场的仪式时间就一定要尽量短 d = (t - s) / 2 + 1,(因为必须大于一半,所以加 1).然后按照每场婚礼可以最晚结束的时间排序 t - d,(因为要满足所有的婚礼,所以尽量解决早点的仪式,腾出时间来给后面的婚礼),维护一个占用时间值即可. #include <cstdio> #incl

POJ 3683 Priest John&#39;s Busiest Day (2-SAT+输出可行解)

题目地址:POJ 3683 第一次做需要输出可行解的题目...大体思路是先用强连通来判断是否有可行解,然后用逆序建图,用拓扑排序来进行染色,然后输出可行解.具体思路见传送门 因为判断的时候少写了一个等号..检查了好长时间..sad... 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #incl

POJ 3683(Priest John&#39;s Busiest Day-强连通分量解决2-SAT)[Template:2-SAT]

Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8144   Accepted: 2769   Special Judge Description John is the only priest in his town. September 1st is the John's busiest day in a year because there is an old le

POJ 3683.Priest John&#39;s Busiest Day 2-SAT

Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10144   Accepted: 3472   Special Judge Description John is the only priest in his town. September 1st is the John's busiest day in a year because there is an old l

HDU 2491 Priest John&#39;s Busiest Day(贪心)

题目链接 题意: n场婚礼 给定每场婚礼的开始和结束时间,要求每场婚礼至少举行一半以上(不包括一半) 如果可行输出YES,否则输出NO 思路: 算出每场婚礼的至少要举行的时间t, 最早的结束时间mid 以最早结束时间mid为第一变量,开始时间s为第二变量从小到大排序 用cnt记录举办完每场婚礼的结束时间 分三种情况: ①加参前当婚礼的时间够不一半 ②果加参婚礼时婚礼已开始,结束时间就加上婚礼一半的时光 ③婚礼没开始,结束时间就是婚礼的最早结束时间mid 代码如下: #include<cstdio