- 一个表达式形如((!)x_i ightarrow(!)x_j),表示(x_i)为真(假)时(x_j)一定为真(假)。
- 给定(n)个(01)变量的三组取值,要求构造若干表达式使得有且仅有这三组解,或判断无法构造。
- (nle50),表达式个数不能超过(500)
简单分类讨论
如果一个变量(x_i)在三组中取值相同(假设都为真),只要用一个表达式(!x_i ightarrow x_i)即可满足条件。
否则,它必然会在某一组中取值与另两组不同,假设是在第(t)组。
对于(t)相同的两个变量(x_i,x_j),确定了(x_i)也就确定了(x_j),可以直接利用两个表达式描述这层关系。
因此最后只需保留(t)不同的变量,此时我们只能在一个变量取到它的第(t)组取值时才能确定其他变量的取值。
实际上,当三种变量都存在的时候是无法构造的,否则显然可行。
代码:(O(n))
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 50
using namespace std;
int n,p[3],a[3][N+5];
namespace Printer
{
#define pc(x) (*C++=x)
#define write(x) (x>9&&pc(x/10+48),pc(x%10+48))
int tot;char FO[100000],*C=FO;I void clear() {fwrite(FO,1,C-FO,stdout);}
I void print(CI x,CI p,CI y,CI q)//x=p -> y=q
{
++tot,!p&&pc('!'),pc('x'),write(x),pc(' '),pc('-'),pc('>'),pc(' '),!q&&pc('!'),pc('x'),write(y),pc('
');
}
}using namespace Printer;
int main()
{
RI i,j,k;for(scanf("%d",&n),k=0;k<=2;++k) for(i=1;i<=n;++i) scanf("%d",a[k]+i);
RI t;for(i=1;i<=n;++i)
{
if(a[0][i]==a[1][i]&&a[0][i]==a[2][i]) {print(i,a[0][i]^1,i,a[0][i]);continue;}//在三组中取值相同
if(!p[t=a[0][i]^a[1][i]?(a[0][i]^a[2][i]?0:1):2]) {p[t]=i;continue;}//尚无这一种变量,记录下来
print(p[t],a[t][p[t]],i,a[t][i]),print(p[t],a[t][p[t]]^1,i,a[t][i]^1);//可以直接确定
}
if(p[0]&&p[1]&&p[2]) return puts("-1"),0;//如果三种变量都存在则无解
for(i=0;i<=2;++i) for(j=0;j<=2;++j) i^j&&p[i]&&p[j]&&(print(p[i],a[i][p[i]],p[j],a[i][p[j]]),0);//只有取到对应组取值时才能确定另一类变量
return printf("%d
",tot),clear(),0;
}