zoj 3656 2-sat 不错的题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了zoj 3656 2-sat 不错的题相关的知识,希望对你有一定的参考价值。
http://acm.zju.edu.cn/onlinejudge/showProblem.do?
problemId=4879
TLE了一下午。然后没办法了 去搜题解 发现思路跟我的差点儿相同 可是就是我的T 后来扩大了数组 然后AC,无语啊
按我的估算 500个点 开到1000+就够了 可是不够 奇怪不懂......
YES or NO的题,一般就是并查集跟2-sat了 目測这道题并查集写起来更easy
http://blog.csdn.net/u011026968/article/details/10823853
看着道题 poj 3678 看完就能发现,仅仅要将每一位都当做poj3678 执行32次 然后就OK
建图方法跟poj3678一样
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <stack> #include <iostream> using namespace std; #define CL(a,b) memset(a,b,sizeof(a)) #define IN(s) freopen(s,"r",stdin) const int MAXN = 6000; int n,b[505][505]; int head[MAXN],dfn[MAXN],low[MAXN],id[MAXN]; int cnt,scnt; stack<int>st; struct Node{ int to,nxt; }edge[1000010];/// inline void addedge(int u,int v,int k) { edge[k].to=v; edge[k].nxt=head[u]; head[u]=k; //printf("u=%d v=%d k=%d\n",u,v,k); } void tarjan(int u) { int v,i,min1=dfn[u]=low[u]=cnt++; st.push(u); for(i=head[u];i!=-1;i=edge[i].nxt) { v=edge[i].to; if(dfn[v]==-1)tarjan(v); min1=min(min1,low[v]); } if(min1<low[u]){low[u]=min1;return;} do { v=st.top(); id[v]=scnt; st.pop(); low[v]=n*2; }while(v!=u); scnt++; } int solve(int pos) { CL(dfn,0xff); CL(id,0xff); CL(head,0xff); CL(low,0xff); scnt=cnt=0; while(!st.empty())st.pop(); int num=0; for(int i=0;i<n;i++) for(int j=0;j<n;j++) { if(i==j)continue;/// int f= (b[i][j]>>pos)&1; ////////// //printf("pos=%d bij=%d f=%d\n",pos,b[i][j],f); if(i%2 && j%2) { if(f) { addedge(i,j+n,num++); addedge(j,i+n,num++); } else { addedge(i+n,i,num++); addedge(j+n,j,num++); addedge(i,j,num++); addedge(j,i,num++); } continue; } if(i%2==0 && j%2==0) { if(f) { addedge(i,i+n,num++); addedge(j,j+n,num++); addedge(i+n,j+n,num++); addedge(j+n,i+n,num++); } else { addedge(j+n,i,num++); addedge(i+n,j,num++); } continue; } if(f) { addedge(i,j+n,num++); addedge(j+n,i,num++); addedge(j,i+n,num++); addedge(i+n,j,num++); } else { addedge(i,j,num++); addedge(j,i,num++); addedge(i+n,j+n,num++); addedge(j+n,i+n,num++); } } int flag=1; for(int i=0;i<n*2;i++) if(dfn[i] == -1) { //////// //printf("tari=%d\n",i); //////// tarjan(i); } for(int i=0;i<n;i++) if(id[i] == id[i+n])//在同一个连通分量 { flag=0; break; } if(flag)return 1; else return 0; } int main() { //IN("zoj3656.txt"); while(~scanf("%d",&n)) { for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",&b[i][j]); int flag=0; for(int i=0;i<n;i++) { if(b[i][i]) { flag=2; puts("NO"); break; } } if(flag==2)continue; for(int i=0;i<n-1;i++) for(int j=i+1;j<n;j++) { if(b[i][j]!=b[j][i]) { flag=2; puts("NO"); break; } } if(flag==2)continue; for(int i=0;i<32;i++) { flag=solve(i); if(flag==0)break; } if(!flag)puts("NO"); else puts("YES"); } return 0; }
并查集的做法代码短了非常多 好流弊的样子 http://blog.csdn.net/lasolmi/article/details/38979207
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <stack> #include <iostream> using namespace std; #define CL(a,b) memset(a,b,sizeof(a)) #define IN(s) freopen(s,"r",stdin) const int MAXN = 6000; int n,b[505][505]; int head[MAXN],dfn[MAXN],low[MAXN],id[MAXN]; int cnt,scnt; stack<int>st; struct Node{ int to,nxt; }edge[1000010];/// inline void addedge(int u,int v,int k) { edge[k].to=v; edge[k].nxt=head[u]; head[u]=k; //printf("u=%d v=%d k=%d\n",u,v,k); } void tarjan(int u) { int v,i,min1=dfn[u]=low[u]=cnt++; st.push(u); for(i=head[u];i!=-1;i=edge[i].nxt) { v=edge[i].to; if(dfn[v]==-1)tarjan(v); min1=min(min1,low[v]); } if(min1<low[u]){low[u]=min1;return;} do { v=st.top(); id[v]=scnt; st.pop(); low[v]=n*2; }while(v!=u); scnt++; } int solve(int pos) { CL(dfn,0xff); CL(id,0xff); CL(head,0xff); CL(low,0xff); scnt=cnt=0; while(!st.empty())st.pop(); int num=0; for(int i=0;i<n;i++) for(int j=0;j<n;j++) { if(i==j)continue;/// int f= (b[i][j]>>pos)&1; ////////// //printf("pos=%d bij=%d f=%d\n",pos,b[i][j],f); if(i%2 && j%2) { if(f) { //addedge(i,j+n,num++); //addedge(j,i+n,num++); addedge(i+n,j,num++); addedge(j+n,i,num++); } else { addedge(i,i+n,num++); addedge(j,j+n,num++); //addedge(i+n,i,num++); //addedge(j+n,j,num++); //addedge(i,j,num++); //addedge(j,i,num++); } continue; } if(i%2==0 && j%2==0) { if(f) { addedge(i+n,i,num++); addedge(j+n,j,num++); //addedge(i,i+n,num++); //addedge(j,j+n,num++); //addedge(i+n,j+n,num++); //addedge(j+n,i+n,num++); } else { addedge(i,j+n,num++); addedge(j,i+n,num++); //addedge(j+n,i,num++); //addedge(i+n,j,num++); } continue; } if(f) { addedge(i,j+n,num++); addedge(j+n,i,num++); addedge(j,i+n,num++); addedge(i+n,j,num++); } else { addedge(i,j,num++); addedge(j,i,num++); addedge(i+n,j+n,num++); addedge(j+n,i+n,num++); } } int flag=1; for(int i=0;i<n*2;i++) if(dfn[i] == -1) { //////// //printf("tari=%d\n",i); //////// tarjan(i); } for(int i=0;i<n;i++) if(id[i] == id[i+n])//在同一个连通分量 { flag=0; break; } if(flag)return 1; else return 0; } int main() { //IN("zoj3656.txt"); while(~scanf("%d",&n)) { for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",&b[i][j]); int flag=0; for(int i=0;i<n;i++) { if(b[i][i]) { flag=2; puts("NO"); break; } } if(flag==2)continue; for(int i=0;i<n-1;i++) for(int j=i+1;j<n;j++) { if(b[i][j]!=b[j][i]) { flag=2; puts("NO"); break; } } if(flag==2)continue; for(int i=0;i<32;i++) { flag=solve(i); if(flag==0)break; } if(!flag)puts("NO"); else puts("YES"); } return 0; }
以上是关于zoj 3656 2-sat 不错的题的主要内容,如果未能解决你的问题,请参考以下文章
ZOJ2112 Dynamic Rank(可持久化线段树套树状数组)