2-SAT,判断任意两条线段是否内部互斥或者外部互斥就可以建图了。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int maxn=8000+5; int M,N; int L[maxn],R[maxn]; struct TwoSAT { int n; vector<int> G[maxn*2]; bool mark[maxn*2]; int S[maxn*2],c; bool dfs(int x) { if(mark[x^1]) return false; if(mark[x]) return true; mark[x]=true; S[c++]=x; for(int i=0;i<G[x].size();i++) if(!dfs(G[x][i])) return false; return true; } void init(int n) { this->n=n; for(int i=0;i<n*2;i++) G[i].clear(); memset(mark,0,sizeof mark); } void add_clause(int x,int y) { G[x].push_back(y^1); G[y].push_back(x^1); } bool solve() { for(int i=0;i<2*n;i+=2) if(!mark[i]&&!mark[i+1]) { c=0; if(!dfs(i)) { while(c>0) mark[S[--c]]=false; if(!dfs(i+1)) return false; } } return true; } }; bool pan(int x,int l,int r) { if(l<x&&x<r) return 1; else return 0; } int main() { while(~scanf("%d%d",&M,&N)) { TwoSAT T; T.init(N); for(int i=0;i<N;i++) { scanf("%d%d",&L[i],&R[i]); if(L[i]>R[i]) swap(L[i],R[i]); } for(int i=0;i<N;i++) { int Le=L[i],Ri=R[i]; for(int j=i+1;j<N;j++) { if(pan(L[j],Le,Ri)==1&&pan(R[j],Le,Ri)==0) { T.add_clause(2*i,2*j);//放内部互斥 T.add_clause(2*j+1,2*i+1);//放外部互斥 } else if(pan(L[j],Le,Ri)==0&&pan(R[j],Le,Ri)==1) { T.add_clause(2*i,2*j);//放内部互斥 T.add_clause(2*j+1,2*i+1);//放外部互斥 } } } if(T.solve()) printf("panda is telling the truth... "); else printf("the evil panda is lying again "); } return 0; }