之前发过一篇2-sat模板的文章http://blog.csdn.net/zck921031/article/details/7712359。再看看今天这题,是不是很像哈。
题目链接http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3656
经典的and or xor运算,六种情况全部上了,⊙﹏⊙b汗啊(去长春赛区的同学们,乃们辛苦了)。
好了,先来说说这道题目。
Bit Magic,嗯哼?bit,一个int有32bit(废话啦),那和这题什么关系呢?要用数组a[]通过位运算得到矩阵b,似乎很难解~~
不过,如果只考虑a,b的其中一个位,很容易发现,a[i]只有两种取值(0,1), 矩阵b对应的是一系列对a的约束条件。取b[i][j]的某个位,0代表a[i] a[j]对应的操作为假,1代表a[i] a[j]对应的操作为真, 这样是不是可以得到很像下表(poj3678)的一个关系。bingo,2-sat模型。
|
|
|
那么,int有32bit怎么办?其实吧,位运算每一位都是相互独立的,我们对每个位做一次2-sat,一共做32次2-sat,只要出现矛盾,直接puts("NO"),否则最后puts("YES"); 对于矩阵b的主对角线的0,我另作了判断,建图是跳过他们,没有关系的。
每次跑强连通子图的时间复杂度是O( (2N)^2 ),跑32次也不是太久,反正时限8s,无所谓啦,抄个强连通分支水过就好。
#include<string.h>
#include<algorithm>
#include <cstdio>
using namespace std;
#define MAXN 1010
int n;
unsigned int b[MAXN][MAXN];
int m[MAXN][MAXN];
int id[MAXN];
int find_components(int n,int mat[][MAXN],int* id){
int ret=0,a[MAXN],b[MAXN],c[MAXN],d[MAXN],i,j,k,t;
for (k=0;k<n;id[k++]=0);
for (k=0;k<n;k++)
if (!id[k]){
for (i=0;i<n;i++)
a[i]=b[i]=c[i]=d[i]=0;
a[k]=b[k]=1;
for (t=1;t;)
for (t=i=0;i<n;i++){
if (a[i]&&!c[i])
for (c[i]=t=1,j=0;j<n;j++)
if (mat[i][j]&&!a[j])
a[j]=1;
if (b[i]&&!d[i])
for (d[i]=t=1,j=0;j<n;j++)
if (mat[j][i]&&!b[j])
b[j]=1;
}
for (ret++,i=0;i<n;i++)
if (a[i]&b[i])
id[i]=ret;
}
return ret;
}
void build_map(int k)
{
memset(m, 0, sizeof(m));
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
if(i == j) continue;
if(i % 2 == 1 && j % 2 == 1)
{
if((b[i][j] & (1<<k)) )
{
m[i][j+n] = 1;
m[j][i+n] = 1;
}
else
{
m[i+n][i] = 1;
m[j+n][j] = 1;
m[i][j] = m[j][i] = 1;
}
}
else if(i % 2 == 0 && j % 2 == 0)
{
if((b[i][j] & (1<<k)) )
{
m[i][i+n] = 1;
m[j][j+n] = 1;
m[i+n][j+n] = m[j+n][i+n] = 1;
}
else
{
m[j+n][i] = 1;
m[i+n][j] = 1;
}
}
else
{
if((b[i][j] & (1<<k)) )
{
m[i][j+n] = m[j+n][i] = 1;
m[j][i+n] = m[i+n][j] = 1;
}
else
{
m[i][j] = m[j][i] = 1;
m[i+n][j+n] = m[j+n][i+n] = 1;
}
}
}
}
void solve()
{
for(int k = 0; k < 32; k++)
{
build_map(k);
memset(id, 0, sizeof(id));
find_components(2*n, m, id);
/*
printf("%d\n",k);
for (int i=0; i<n; i++,puts(""))
for (int j=0; j<n; j++)
{
printf("%d ",b[i][j]&(1<<k));
}
for(int i = 0; i < n; i++)
{
printf("id[%d] = %d, id[%d] = %d\n", i, id[i], i+n, id[i+n]);
}
*/
for(int i = 0; i < n; i++)
if(id[i] == id[i+n])
{
printf("NO\n");
return;
}
}
printf("YES\n");
}
int main()
{
while(scanf("%d",&n) != EOF)
{
int i, j;
memset(id, 0, sizeof(id));
memset(b, 0, sizeof(b));
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
scanf("%d",&b[i][j]);
bool flag = true;
for(i = 0; i < n; i++)
if(b[i][i]) { flag = false; break; }
if(flag == false)
{
printf("NO\n");
continue;
}
solve();
}
return 0;
}