POJ 3684 Priest John's Busiest Day 2-SAT+输出路径

强连通算法判断是否满足2-sat,然后反向建图,拓扑排序+染色。

一种选择是从 起点开始,另一种是终点-持续时间那个点 开始。

若2个婚礼的某2种时间线段相交,则有矛盾,建边。

容易出错的地方就在于判断线段相交。

若s1<e2&&s2<e1则相交

输出路径的做法可以参考论文2-SAT解法浅析

#include <iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 5555
#define MAXM 3000010
struct node
{
    int to,next;
}edge[MAXM];
int head[MAXN],en;
int low[MAXN],dfn[MAXN],stack[MAXN],cho[MAXN],top,set[MAXN],col,num,color[MAXN],counts[MAXN];
bool vis[MAXN],instack[MAXN];
int n;
int m;
void addedge(int a,int b)
{
    edge[en].to=b;
    edge[en].next=head[a];
    head[a]=en++;
}
int son[MAXN];
void tarjan(int u)
{

    vis[u]=1;
    dfn[u]=low[u]=++num;
    instack[u]=true;
    stack[++top]=u;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!vis[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else
            if(instack[v])
                low[u]=min(dfn[v],low[u]);
    }
    if(dfn[u]==low[u])
    {
        int j;
        col++;
        do
        {
            j=stack[top--];
            instack[j]=false;
          set[j]=col;
        }
        while (j!=u);
    }
}
void init()
{
    en=top=col=num=0;
    memset(head,-1,sizeof(head));
    memset(instack,0,sizeof(instack));
    memset(vis,0,sizeof(vis));
    memset(set,-1,sizeof(set));
    memset(color,0,sizeof(color));
    memset(counts,0,sizeof(counts));
    memset(cho,0,sizeof(cho));
}
struct node2
{
    int st,ed,la;
}p[2005];
vector<int> g[2005];
void topsort()
{
	queue<int> q;
	for(int i=1;i<=col;i++)
	{
		if(counts[i]==0)
			q.push(i);
	}
	while(!q.empty())
	{
		int j=q.front();
		if(!color[j]) color[j]=1,color[son[j]]=-1;
		q.pop();
		for(int k=0;k<g[j].size();k++)
		{
			if(--counts[g[j][k]]==0)
				q.push(g[j][k]);
		}
	}
}
void print(int t1,int t2)
{

     printf("%02d:%02d",t1/60,t1%60);
    printf(" %02d:%02d\n",t2/60,t2%60);
}
int main()
{
    int a,b,c,d,e;
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d:%d%d:%d%d",&a,&b,&c,&d,&e);
            p[i].st=a*60+b;
            p[i].ed=c*60+d;
            p[i].la=e;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i==j) continue;
                if(p[i].st<p[j].st+p[j].la && p[i].st+p[i].la>p[j].st) {addedge(i,j+n);}
                if(p[i].st<p[j].ed && p[i].st+p[i].la>p[j].ed-p[j].la) {addedge(i,j);}

                if(p[i].ed-p[i].la<p[j].st+p[j].la && p[i].ed>p[j].st) {addedge(i+n,j+n);}
                if(p[i].ed-p[i].la<p[j].ed && p[i].ed>p[j].ed-p[j].la) {addedge(i+n,j);}
            }
        }
        for(int i=1;i<=n*2;i++)
            if(!vis[i])tarjan(i);
        int ok=1;
        for(int i=1;i<=n;i++)
        {
            if(set[i]==set[i+n]) {ok=0;break;}
            son[set[i]]=set[i+n];
            son[set[i+n]]=set[i];
        }
        if(ok==0) {puts("NO");continue;}
        else puts("YES");
        for(int i=1;i<=col;i++) g[i].clear();
        for(int i=1;i<=2*n;i++)
            for(int j=head[i];~j;j=edge[j].next)
            if(set[i]!=set[edge[j].to])
            {
                g[set[edge[j].to]].push_back(set[i]);
                counts[set[i]]++;
            }
        topsort();

        for(int i=1;i<=2*n;i++)
        {
            if(color[set[i]]==1) cho[i]=1;
        }
        for(int i=1;i<=n;i++)
        {
            if(cho[i]) print(p[i].st,p[i].st+p[i].la);
            else print(p[i].ed-p[i].la,p[i].ed);
        }
    }
    return 0;
}
/*
3
08:00 09:00 30
08:15 09:00 20
08:00 09:00 30
*/

POJ 3684 Priest John's Busiest Day 2-SAT+输出路径

时间: 2024-12-11 13:43:25

POJ 3684 Priest John's Busiest Day 2-SAT+输出路径的相关文章

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

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

[题目链接] http://poj.org/problem?id=3683 [题目大意] 每个婚礼有两个时段可以进行特别仪式,特别仪式必须要有神父在场, 神父只有一个,问是否能满足所有婚礼的需求, [题解] 因为两个时段必须要满足一个时段,所以如果一个时段被占用那么另一个时段必须被空出来, 我们根据各个婚礼两个时段之间的冲突关系建边,之后跑2-SAT,判断是否冲突, 若无冲突则输出方案. [代码] #include <cstdio> #include <algorithm> #in

POJ 3683 Priest John&#39;s Busiest Day(2-SAT+方案输出)

Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10010   Accepted: 3425   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

POJ 3683 Priest John&#39;s Busiest Day 【2-Sat】

这是一道裸的2-Sat,只要考虑矛盾条件的判断就好了. 矛盾判断: 对于婚礼现场 x 和 y,x 的第一段可以和 y 的第一段或者第二段矛盾,同理,x 的第二段可以和 y 的第一段或者第二段矛盾,条件是 x 的 1或2 段与 y 的 1或2 段有重合,那么选了 x 某一段就不能选择其矛盾的那一段,那就只能选择 y 中的另一段,建立一条 x (u)-> y ( v的对立 ),同理,x (u的对立)<- y ( v ) . 真的,2-sat千万不要用邻接链表!!!卡死卡死卡死!!!稠密图!!!不要

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.模板题. #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