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