Description
有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,
其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。
你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。
对于任意一个开关,最多只能进行一次开关操作。
你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)
输入格式
输入第一行有一个数K,表示以下有K组测试数据。
每组测试数据的格式如下:
第一行 一个数N(0 < N < 29)。
第二行 N个0或者1的数,表示开始时N个开关状态。
第三行 N个0或者1的数,表示操作结束后N个开关的状态。
接下来 每行两个数I J,表示如果操作第 I 个开关,第J个开关的状态也会变化。
每组数据以 0 0 结束。
输出格式
如果有可行方法,输出总数,否则输出Oh,it's impossible~!! 。
Solution
每个开关只能操作一次,求一个目标状态
可设数组x,x[i]表示是(取值为 1 )否(取值为 0 )对第 i 个开关操作,任务是求出x[i]
参照开关之间的关系,我们可以对每个开关列一个方程,一共 n 个方程
第 i 个方程等号右边的第 j 个单项式为 a[i][j]*x[j] ,
a[i][j]表示操作开关 j 是(取值为1)否(取值为0)会影响开关 i 的状态
等号右边为第 i 个开关起始状态^目标状态
于是可以用高斯消元求这个线性方程组的解(lyd大佬码风太强啦)
Code
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
int a[30],T,n,x,y,ans;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
a[i]^=x,a[i]|=(1<<i);
}
while(~scanf("%d%d",&x,&y) && x && y)
a[y]|=(1<<x);
ans=1;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
if(a[j]>a[i]) swap(a[i],a[j]);
if(a[i]==1)
{
ans=0;
break;
}
if(a[i]==0)
{
ans=1<<(n-i+1);
break;
}
for(int k=1;k<=n;k++)
if((a[i]>>k)&1)
{
for(int j=1;j<=n;j++)
if(i!=j && (a[j]>>k)&1) a[j]^=a[i];
break;
}
}
if(ans==0) puts("Oh,it's impossible~!!");
else printf("%d\n",ans);
}
return 0;
}
来源:https://www.cnblogs.com/hsez-cyx/p/12363542.html