poj 3683 Priest John's Busiest Day

http://poj.org/problem?id=3683

标准的2-sat 而且是需要输出路径的 

一直纠结 缩点后建反向图 再利用拓扑排序那一点到底是怎么弄的  原来是自己的拓扑排序没学好 晕

还有刚开始学邻接表的时候一直用动态的 就是没加一条边都要申请一个 new node

没想到这次就超时了  因为边太多了  改成静态的直接100ms+  差距太大了 以后不敢再用动态的了

代码:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<string>

#include<vector>

#include<map>

#include<queue>

#include<stack>

#include<cmath>

#define LL long long



using namespace std;



const int N=2005;

vector<int>ve[2005];//保存环

int head1[N],I1;

int head2[N],I2;

struct ss1

{

    int j,next;

}side1[N*1000];//初始邻接表

struct ss2

{

    int j,next;

}side2[N*1000];//缩点后 反向邻接表

struct T

{

    int st,et;

}setime[N];

int dfn[N];

int low[N];

bool in[N];

bool visited[N];

int deep;

int f[N];

stack<int>str;

queue<int>qt;

int num[N];//拓扑排序计数

int sele[N];//选择 0 为未选 1为选 -1为不选

void build(int i,int j)

{

    side1[I1].j=j;

    side1[I1].next=head1[i];

    head1[i]=I1++;

}

void rebuild(int i,int j)

{

    side2[I2].j=j;

    side2[I2].next=head2[i];

    head2[i]=I2++;

}

void Tarjan(int x)//判环 缩点

{

    visited[x]=true;

    str.push(x);

    in[x]=true;

    dfn[x]=low[x]=deep++;

    int t=head1[x];

    while(t!=-1)

    {

        int k=side1[t].j;

        if(visited[k]==false)

        {

            Tarjan(k);

            low[x]=min(low[x],low[k]);

        }else if(in[k]==true)

        {

            low[x]=min(low[x],dfn[k]);

        }

        t=side1[t].next;

    }

    if(low[x]==dfn[x])

    {

        while(str.top()!=x)

        {

            int k=str.top();

            str.pop();

            in[k]=false;

            f[k]=x;

            ve[x].push_back(k);

        }

        int k=str.top();

        str.pop();

        in[k]=false;

        f[k]=x;

    }



}

bool same(int i,int j)//时间是否冲突

{

    if(setime[i].et<=setime[j].st)

    return false;

    if(setime[j].et<=setime[i].st)

    return false;

    return true;

}

void fsearch(int x)//反向建邻接表 只建缩点 

{

    int t=head1[x];

    while(t!=-1)

    {

        int k=side1[t].j;

        if(f[x]!=f[k])

        {

            rebuild(f[k],f[x]);

            ++num[f[x]];//拓扑排序 计数

        }

        t=side1[t].next;

    }

}

void subside(int x)//拓扑中 用掉一个边 将它指向的点的计数减一 为0的话 入队列 

{

    int t=head2[x];

    while(t!=-1)

    {

        --num[side2[t].j];

        if(num[side2[t].j]==0)

        qt.push(side2[t].j);

        t=side2[t].next;

    }

}

void color(int k,int n)//将一个环内的点 然成相同颜色

{

    int l1=k;

    int l2=(k<n)?k+n:k-n;

    l1=f[l1];l2=f[l2];

    sele[l1]=1;

    for(unsigned int i=0;i<ve[l1].size();++i)

    sele[ve[l1][i]]=1;

    sele[l2]=-1;

    for(unsigned int i=0;i<ve[l2].size();++i)

    sele[ve[l2][i]]=-1;

}

void print(int i)//输出

{

    int t1=setime[i].st;

    int t2=setime[i].et;

    printf("%02d:%02d %02d:%02d\n",t1/60,t1%60,t2/60,t2%60);

}

int main()

{

    //freopen("data.txt","r",stdin);

    int n;

    while(scanf("%d",&n)!=EOF)

    {



        int l1,l2,k1,k2,d;

        char c1,c2;

        memset(head1,-1,sizeof(head1));

        I1=0;

        for(int i=0;i<n;++i)

        {

            scanf("%d%c%d %d%c%d %d",&l1,&c1,&l2,&k1,&c2,&k2,&d);

            setime[i].st=l1*60+l2;

            setime[i].et=l1*60+l2+d;

            setime[i+n].et=k1*60+k2;

            setime[i+n].st=k1*60+k2-d;

            for(int j=0;j<i;++j)

            {

                if(same(j,i))//判断是否冲突

                {

                    build(j,i+n);build(i,j+n);

                }

                if(same(j+n,i))

                {

                    build(j+n,i+n);build(i,j);

                }

                if(same(j,i+n))

                {

                    build(j,i);build(i+n,j+n);

                }

                if(same(j+n,i+n))

                {

                    build(j+n,i);build(i+n,j);

                }

            }

        }

        while(!str.empty())

        str.pop();

        memset(dfn,-1,sizeof(dfn));

        memset(low,-1,sizeof(low));

        memset(in,false,sizeof(in));

        memset(visited,false,sizeof(visited));

        for(int i=0;i<2*n;++i)

        f[i]=i;

        deep=0;

        for(int i=0;i<n;++i)

        ve[i].clear();

        int l;

        for(l=0;l<n;++l)

        {

            if(visited[l]==false)

            Tarjan(l);

            if(f[l]==f[l+n])

            break;

        }

        if(l<n)

        printf("NO\n");

        else

        {

            printf("YES\n");

            memset(head2,-1,sizeof(head2));

            I2=0;

            for(int i=0;i<2*n;++i)

            fsearch(i);//重新建反向图

            for(int i=0;i<2*n;++i)

            if(f[i]==i&&num[i]==0)

            qt.push(i);//拓扑后为0的进队列

            memset(sele,0,sizeof(sele));

            while(!qt.empty())

            {

                int k=qt.front();

                qt.pop();

                if(sele[k]==0)//为染色的染色

                color(k,n);

                subside(k);

            }

            for(int i=0;i<n;++i)

            {

                if(sele[i]==1)

                print(i);

                else

                print(i+n);

            }

        }

    }

    return 0;

}

  

你可能感兴趣的:(poj)