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;
}

  

posted on 2012-08-16 08:59  夜->  阅读(161)  评论(0编辑  收藏  举报