『开关问题 异或高消』
<更新提示>
<第一次更新>
<正文>
开关问题(POJ 1830)#
Description#
有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。
你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)
Input Format#
输入第一行有一个数K,表示以下有K组测试数据。 每组测试数据的格式如下: 第一行 一个数N(0 < N < 29) 第二行 N个0或者1的数,表示开始时N个开关状态。 第三行 N个0或者1的数,表示操作结束后N个开关的状态。 接下来 每行两个数I J,表示如果操作第 I 个开关,第J个开关的状态也会变化。每组数据以 0 0 结束。
Output Format#
如果有可行方法,输出总数,否则输出“Oh,it's impossible~!!” 不包括引号
Sample Input#
2
3
0 0 0
1 1 1
1 2
1 3
2 1
2 3
3 1
3 2
0 0
3
0 0 0
1 0 1
1 2
2 1
0 0
Sample Output#
4
Oh,it's impossible~!!
解析#
设xi代表是否操作了第i个开关,按了为1,不按为0。fij代表开关i和开关j的联系情况,按下j会影响i则fij=1,反之fij=0,对于任意的i,令fii=1。
如果将第i个开关最后是否变化记为pi的话,就可以得到异或方程组:
{f11x1 xor f12x2 xor ... xor f1nxn=p1f21x1 xor f22x2 xor ... xor f2nxn=p2 ...fn1x1 xor fn2x2 xor ... xor fnnxn=pn
同样地,这个方程组也是可以高斯消元的,只需将加减操作改为异或即可。
对于本题,求的是方案数,那么我们分高斯消元的三种情况处理即可。当方程组恰好有解时,方案数为1,当方程组无解时,方案数为0,当方程组无穷解时,记录下自由元的个数p,由于每个x可以取1或0,所以方案数为2p。
由于本题增广矩阵中所有元素非1即0,所以可以状态压缩一下,方便运算。
Code:
#include <bits/stdc++.h>
using namespace std;
const int N=30;
int n,f[N],ans,t;
inline void input(void)
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&f[i]);
int x,y;
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
f[i] ^= x;
}
while ( scanf("%d%d",&x,&y) && x && y )
f[y] |= 1 << x;
}
inline void init(void)
{
for (int i=1;i<=n;i++)
f[i] |= 1 << i;
}
inline void Gauss(void)
{
ans = 1;
for (int i=1;i<=n;i++)
{
for (int j=i+1;j<=n;j++)
if ( f[j] > f[i] )
swap(f[j],f[i]);
if (!f[i]){ans = 1 << (n-i+1);break;}
if (f[i]==1){ans = 0;break;}
for (int j=n;j>=1;j--)
{
if (f[i] >> j & 1)
{
for (int k=1;k<=n;k++)
if ( i ^ k && ( f[k] >> j & 1 ) )
f[k] ^= f[i];
break;
}
}
}
}
int main(void)
{
freopen("switch.in","r",stdin);
freopen("switch.out","w",stdout);
scanf("%d",&t);
while (t--)
{
input();
init();
Gauss();
if ( !ans )printf("Oh,it's impossible~!!\n");
else printf("%d\n",ans);
}
return 0;
}
<后记>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】博客园2025新款「AI繁忙」系列T恤上架,前往周边小店选购
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步