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