蓝书(算法竞赛进阶指南)刷题记录——POJ1830 开关问题(高斯消元)

题目:POJ1830.
题目大意:给定一个长度为为 n n n的初始 01 01 01序列 a a a,要求你把序列操作(给一些位置取反)成一个给定的 01 01 01序列.给出一些关系 i   j i\,j ij,表示若 i i i被操作则 j j j也要被操作.
1 ≤ n &lt; 29 1\leq n&lt; 29 1n<29.

设每一个开关的初始状态为 b i b_i bi,结束状态 e i e_i ei a i , j = 1 / 0 a_{i,j}=1/0 ai,j=1/0表示第 i i i个数会/不会被第 j j j个数影响, x i x_i xi表示第 i i i个点被操作几次.我们发现这个东西可以列成一个异或方程组:
{ a 1 , 1 x 1 &ThinSpace; x o r &ThinSpace; a 1 , 2 x 2 &ThinSpace; x o r &ThinSpace; ⋯ &ThinSpace; x o r &ThinSpace; a 1 , n x = b 1 &ThinSpace; x o r &ThinSpace; e 1 a 2 , 1 x 1 &ThinSpace; x o r &ThinSpace; a 2 , 2 x 2 &ThinSpace; x o r &ThinSpace; ⋯ &ThinSpace; x o r &ThinSpace; a 2 , n x = b 2 &ThinSpace; x o r &ThinSpace; e 2 ⋮ a n , 1 x 1 &ThinSpace; x o r &ThinSpace; a n , 2 x 2 &ThinSpace; x o r &ThinSpace; ⋯ &ThinSpace; x o r &ThinSpace; a n , n x = b n &ThinSpace; x o r &ThinSpace; e n \left\{\begin{matrix} a_{1,1}x_1\,xor\,a_{1,2}x_2\,xor\,\cdots\,xor\,a_{1,n}x=b_1\,xor\,e_1\\ a_{2,1}x_1\,xor\,a_{2,2}x_2\,xor\,\cdots\,xor\,a_{2,n}x=b_2\,xor\,e_2\\ \vdots\\ a_{n,1}x_1\,xor\,a_{n,2}x_2\,xor\,\cdots\,xor\,a_{n,n}x=b_n\,xor\,e_n \end{matrix}\right. a1,1x1xora1,2x2xorxora1,nx=b1xore1a2,1x1xora2,2x2xorxora2,nx=b2xore2an,1x1xoran,2x2xorxoran,nx=bnxoren

我们得到了一个异或方程组,发现异或方程组其实很容易解,把加减操作换成异或即可.而且我们发现这个方程中一行只有 30 30 30 0 / 1 0/1 0/1,所以可以状态压缩.

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=29;

int a[N+9],n,ans;

int Gauss(int *a,int n){
  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) return n-i+1;
  	if (a[i]==1) return -1;
  	for (int k=n;k>=1;--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;
	  }
  }
  return 0;
}

Abigail into(){
  scanf("%d",&n);
  int x,y;
  for (int i=1;i<=n;++i)
  	scanf("%d",&a[i]);
  for (int i=1;i<=n;++i){
    scanf("%d",&x);
    a[i]^=x;
  }
  while (~scanf("%d%d",&x,&y)&&x+y)
  	a[y]|=1<<x;
}

Abigail work(){
  for (int i=1;i<=n;++i)
    a[i]|=1<<i;
  ans=Gauss(a,n);
}

Abigail outo(){
  if (ans==-1) puts("Oh,it's impossible~!!");
  else printf("%d\n",1<<ans);
}

int main(){
  int T;
  scanf("%d",&T);
  while (T--){
    into();
    work();
    outo();
  }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值