题目
输入
输出
样例输入
2 2 10 01 11 10 11 01 3 111 111 000 100 010 001 111 111 000
样例输出
NO YES
思路
本题如果我们用暴力做法,时间复杂度为O(n^3),会TLE。
首先,我们知道等式两边同时乘一个数,等式仍然成立。
而这个定理在等式中仍然成立,我们折A*B=C,则A*B*D=C*D。(A,B,C,D均为矩阵)。
前提是:A是M列,B和D都是M行。
所以,我们可以优化我们的暴力。我们设D为N行一列,题目即可变为判断A*B*D=C*D是否成立。然后再使用一个乘法结合律,把A*B*D变为A*(B*D)。
然后我们来看一下时间复杂度
E=B*D(O(N^2))
F=A*E(O(N^2))
G=C*D(O(N^2))
由于这题是01矩阵,1+1=0,所以需要用到位运算。
而且,可能原本不相等的,乘了个D就相等了。
所以我们随机生成10次D,不相等直接输出NO,否则输出YES。
具体代码
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<cstring>
using namespace std;
int n,t,bz=1,a[1005][1005],b[1005][1005],c[1005][1005],x[1005],y[1005],z[1005],f[1005];
int main()
{
srand(time(NULL));
scanf("%d",&t);
for (int q=1;q<=t;q++)
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%1d",&a[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%1d",&b[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%1d",&c[i][j]);
bz=1;
for (int p=1;p<=10;p++)
{
for (int i=1;i<=n;i++)
f[i]=rand()%2+0;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(z,0,sizeof(z));
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
x[i]=x[i]^(b[i][j]&f[j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
y[i]=y[i]^(a[i][j]&x[j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
z[i]=z[i]^(c[i][j]&f[j]);
for (int i=1;i<=n;i++)
{
if (y[i]!=z[i])
{
bz=0;
printf("NO\n");
break;
}
}
if (bz==0) break;
}
if (bz==1) printf("YES\n");
}
return 0;
}