2-SAT,不要所有位置全部建好边再判断,那样会MLE的。
正解是,每一位建好边,就进行一次2-SAT。
#include<cstdio> #include<cstring> #include<cmath> #include<stack> #include<queue> #include<algorithm> using namespace std; const int maxn=1000+10; int N; int B[505][505]; stack<int>S; vector<int>G[maxn]; vector<int>FG[maxn]; int Belong[maxn]; int flag[maxn]; int Block; void init() { for(int i=0; i<maxn; i++) G[i].clear(); for(int i=0; i<maxn; i++) FG[i].clear(); memset(Belong,0,sizeof Belong); memset(flag,0,sizeof flag); while(!S.empty()) S.pop(); Block=0; } void addEdge(int x,int y) { G[x].push_back(y); FG[y].push_back(x); } void dfs1(int now) { flag[now]=1; for(int i=0; i<G[now].size(); i++) if(!flag[G[now][i]]) dfs1(G[now][i]); S.push(now); } void dfs2(int now) { Belong[now]=Block; for(int i=0; i<FG[now].size(); i++) if(!Belong[FG[now][i]]) dfs2(FG[now][i]); } bool judge() { for(int i=0; i<2*N; i++) if(!flag[i]) dfs1(i); while(!S.empty()) { int Top=S.top(); S.pop(); if(!Belong[Top]) { Block++; dfs2(Top); } } for(int i=0; i<N; i++) if(Belong[i]==Belong[i+N]) return 0; return 1; } int main() { while(~scanf("%d",&N)) { for(int i=0; i<N; i++) for(int j=0; j<N; j++) scanf("%d",&B[i][j]); int Base=1; int ans=1; for(int i=0; i<N; i++) if(B[i][i]!=0) ans=0; for(int i=0; i<N; i++) for(int j=0; j<N; j++) if(B[i][j]!=B[j][i]) ans=0; if(ans==0) { printf("NO\n"); continue; } for(int k=0; k<31; k++) { init(); for(int i=0; i<N; i++) { for(int j=i+1; j<N; j++) { int c=B[i][j]&(1<<k); if(i%2==1&&j%2==1) { if(c) { addEdge(i+N,j); addEdge(j+N,i); } else { addEdge(i,i+N); addEdge(j,j+N); } } else if(i%2==0&&j%2==0) { if(c) { addEdge(i+N,i); addEdge(j+N,j); } else { addEdge(i,j+N); addEdge(j,i+N); } } else { if(c) { addEdge(i,j+N); addEdge(j,i+N); addEdge(i+N,j); addEdge(j+N,i); } else { addEdge(i,j); addEdge(j,i); addEdge(i+N,j+N); addEdge(j+N,i+N); } } } } if(!judge()) { ans=0; break; } } if(ans) printf("YES\n"); else printf("NO\n"); } return 0; }