ZOJ Problem Set - 3656 Bit Magic
飞机票: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4879
分析:搞了一天的2-sat了。。。感觉还是迷迷糊糊真是菜比~~~好了。。。不扯了。。。直接正题:
题意:题意就是给你个矩阵。。。然后求是否有数组满足那段程序的。。。程序自己看啊。。。请点击飞机票。。。这种题怎么变成2-sat。。。烧脑烧力啊。。。,先预处理对角线是否为0和对称点是否一样。。然后只要把每个位单独处理即可~~~。。。坦白地说:对于矩阵的一个元素b[i][j]。。。如果i%2==0&&j%2==0则a[i]&a[j]=b[i][j]。。。这里就可以用到前面文章的内容了。。。就是说a[i]的第k为&a[j]的第k位=b[i][j]的第k位(注:2进制下)然后运用前面文章的信息。不妨设当前点i为1则是i*2,为0则是i*2+1那么就可以建图了
AND 结果为1:建边 x*2+1->x*2,y*2+1->y*2 (两个数必须全为1)
AND 结果为0:建边 y*2->x*2+1,x*2->y*2+1 (两个数至少有一个为0)
OR 结果为1:建边 x*2+1->y*2,2*y+1->x*2 (两个数至少有一个为1)
OR 结果为0:建边 x*2->x*2+1,y*2->y*2+1 (两个数必须全为0)
XOR 结果为1:建边 x*2->y*2+1,y*2->x*2+1,y*2+1->x*2,x*2+1->y*2 (两个数必须不同)
XOR 结果为0:建边 x*2->y*2,y*2->x*2,x*2+1->y*2+1,y*2+1->x*2+1 (两个数必须相同)
这样要处理最多30次。。。因为b[i][j]有范围限制,然后每一次都跑一遍。。。只要有不符合就直接啪啦:NO,如果都想。。YES!啪啪啪~但是速度不快啊。。。不过AC还是轻轻松松的~~~
/* Author:Chieh Grow up happy */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <map> #include <queue> #include <stack> #include <vector> #define LL long long using namespace std; const int maxn=1234; vector<int> V[maxn]; int ai[567][567]; int n; void init() { for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { scanf("%d",&ai[i][j]); } } } bool instack[maxn]; int dfn[maxn],low[maxn],sta[maxn],belong[maxn],indexx,scnt,cntnum; void tarjan(int u) { dfn[u]=low[u]=indexx++; instack[u]=1; sta[++scnt]=u; for(int i=0; i<V[u].size(); i++) { int v=V[u][i]; if(dfn[v]==-1) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v])low[u]=min(dfn[v],low[u]); } if(dfn[u]==low[u]) { for(int v=-1; v!=u; scnt--) { v=sta[scnt]; instack[v]=0; belong[v]=cntnum; } cntnum++; } } void play() { for(int i=0; i<n; i++) { if(ai[i][i]!=0) { printf("NO\n"); return; } } int MAX=0; for(int i=0; i<n; i++) { for(int j=i+1; j<n; j++) { MAX=max(MAX,ai[i][j]); if(ai[i][j]!=ai[j][i]) { printf("NO\n"); return; } } } int o=(1<<30); while(o>MAX){ o=o>>1; } for(int i=1; i<=100; i++) { if(o==0)break; for(int j=0; j<2*n; j++)V[j].clear(); bool ju=0; for(int j=0; j<n; j++) { for(int k=0; k<n; k++) { if(j==k)continue; int u=(j)*2; int v=(k)*2; int c=0; if(ai[j][k]-o>=0) { ju=1; ai[j][k]-=o; c=1; } if(j%2==0&&k%2==0) { if(c==0) { V[u].push_back(v^1); V[v].push_back(u^1); } else { V[u^1].push_back(u); V[v^1].push_back(v); } } else if(j%2==1&&k%2==1) { if(c==0) { V[u].push_back(u^1); V[v].push_back(v^1); } else { V[u^1].push_back(v); V[v^1].push_back(u); } } else { if(c==0) { V[u].push_back(v); V[v].push_back(u); V[u^1].push_back(v^1); V[v^1].push_back(u^1); } else { V[u].push_back(v^1); V[v].push_back(u^1); V[v^1].push_back(u); V[u^1].push_back(v); } } } } o=o>>1; if(!ju) { continue; } indexx=cntnum=0; scnt=-1; memset(dfn,-1,sizeof(dfn)); memset(instack,0,sizeof(instack)); for(int j=0; j<2*n; j++) { if(dfn[j]==-1)tarjan(j); } for(int j=0; j<n; j++) { if(belong[j*2]==belong[j*2+1]) { printf("NO\n"); return; } } } printf("YES\n"); } int main() { while(scanf("%d",&n)!=EOF) { init(); play(); } // cout << "Hello world!" << endl; return 0; }