poj 1830 开关问题

    这道题是个十分有趣的数学题。有n个开关,这n个开关两两之间可能有着关系,如果有关系,按下这个开关,另一个开关的状态也会改变。先给你n个开关的初始状态,再给你n个开关的最终状态,然后告诉你开关之间的关系,问你能不能通过调整开关使达到最终状态,如果能,求方案的数量。

    我们用0,1分别表示开关的两个不同状态,对于每个开关,我们知道其他的n-1个开关与它的关系。这个开关是通过哪个状态变成了最终状态,这个设为未知量xi。那么就有n个未知量,关于未知量的方程就需要用到我们之前储存的关系来建立增广矩阵。假如按了i,j也会随着变化,那我们就把a【j】【i】的系数存为1,否则为0。第i个方程,存的a【i】【j】=1代表按j会改变i,每个方程的常数项是第i个开关的初始状态与最终状态的异或值。然后我们就得到了n个关于n个开关的方程组。异或运算其实就是不进位的加法运算,我们仍然用高斯消元解出增广矩阵。消除完之后,剩下的自由元的数量为k,那么ans=2^k。如果存在0=1这种情况,则无解。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,t,ans,a[40];
int main()
{
	scanf("%d",&t);
	while(t--){
		memset(a,0,sizeof(a));
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		for(int i=1,j;i<=n;i++){
			scanf("%d",&j);
			a[i]^=j;
			a[i]|=(1<<i);// a[i][i]=1
		}
		int x,y;
		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[j],a[i]);
			if(a[i]==0){
				ans=1<<(n-i+1);break;
			}
			if(a[i]==1){
				ans=0;break;
			}
			for(int k=n;k;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) printf("Oh,it's impossible~!!\n");
		else printf("%d\n",ans);
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值