题解:
2-sat
然后不用拓扑
直接强连通的逆序就可以了
代码:
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int N=2005; int flag[N],ans,l,n; int ne[N*N],fi[N],a[N],b[N],zz[N*N],num,t,zhan[N],dfn[N],low[N],an[N]; void jb(int x,int y) { ne[++num]=fi[x]; fi[x]=num; zz[num]=y; } void dfs(int x) { low[x]=dfn[x]=++l; zhan[++t]=x; flag[x]=true; for (int i=fi[x];i!=0;i=ne[i]) { if (an[zz[i]])continue; if(!dfn[zz[i]])dfs(zz[i]); if(!flag[zz[i]])low[x]=min(low[x],dfn[zz[i]]);else low[x]=min(low[x],low[zz[i]]); } if (dfn[x]==low[x]) { ans++; while (zhan[t]!=x) { flag[zhan[t]]=false; an[zhan[t--]]=ans; } an[zhan[t--]]=ans; flag[x]=false; } } int read() { int x=0;char c; for (;c<‘0‘||c>‘9‘;c=getchar()); for (;c>=‘0‘&&c<=‘9‘;c=getchar())x=x*10+c-48; return x; } int pd(int x,int y) { if (a[x]>a[y])swap(x,y); return b[x]>a[y]; } void sget(int x) { if (x<10)printf("0"); printf("%d",x); } int main() { scanf("%d",&n); for (int i=0;i<n;i++) { a[i]=read()*60+read(); b[i+n]=read()*60+read(); b[i]=read();a[i+n]=b[i+n]-b[i]; b[i]+=a[i]; } for (int i=0;i<2*n;i++) for (int j=i+1;j<2*n;j++) if (i%n!=j%n&&pd(i,j)) jb(i,(j+n)%(2*n)),jb(j,(i+n)%(2*n)); for (int i=0;i<2*n;i++) if (!dfn[i])dfs(i); for (int i=0;i<n;i++) if (an[i]==an[i+n]) { puts("NO"); return 0; } puts("YES"); for (int i=0;i<n;i++) if (an[i]<an[i+n]) { sget(a[i]/60);printf(":"); sget(a[i]%60);printf(" "); sget(b[i]/60);printf(":"); sget(b[i]%60); puts(""); } else { sget(a[i+n]/60);printf(":"); sget(a[i+n]%60);printf(" "); sget(b[i+n]/60);printf(":"); sget(b[i+n]%60); puts(""); } return 0; }