POJ 1830 开关问题

1、本题用高斯消元法做,构造方程是难点。用G【i】【j】表示灯i是否被灯j控制,x【i】表示是否按下开关i,则本题相当于解异或方程组:

e[a] = (xa * G[a][a]) ^ (xb * G[a][b]) ^ (xc*G[a][c]) ^ f[a]

e[b] = (xa * G[b][a]) ^ (xb * G[b][b]) ^ (xc*G[b][c]) ^ f[b]

e[c] = (xa * G[c ][a]) ^ (xb * G[c][b]) ^ (xc*G[c][c]) ^ f[c]
2、Gauss函数res返回自由元的个数,则答案就是1<<res,注意,如果存在这样的情况:某一行的1到n列全为0,而第n+1列为1,则输出无解。

3、注意,自己可以控制自己,所以G【i】【i】一定为1。

4、异或运算相当于相加模2。要记住这个结论。为什么两行“相减”的时候也是用的异或运算呢?因为异或运算的逆运算还是异或。打个比方,a+b=c,c-b=a,而a^b=c,c^b=a,这里的异或符号就起到了“减号"的作用。当然,用“相减模2”的思想考虑也是可以的,因为真值表一样,所以“相减模2”和“异或”是等价的。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[30],e[30],G[30][30],ans[30];
bool l[30];
int Gauss(int a[][30],bool l[],int ans[],const int &n){
    int res=0,r=1;
 for(int i=1;i<=n;i++)
  l[i]=false;
 for(int i=1;i<=n;i++){
  for(int j=r;j<=n;j++)
   if(a[j][i]>0){
       for(int k=i;k<=n+1;k++)
     swap(a[j][k],a[r][k]);
    break;
   }
       if(a[r][i]==0){
         res++;
      continue;
    }
    for(int j=1;j<=n;j++)
     if(j!=r&&a[j][i]>0){
         for(int k=i;k<=n+1;k++)
                      a[j][k]^=a[r][k];
     }
    l[i]=true;r++;
 }
 for(int i=1;i<=n;i++)
    if(l[i])
     for(int j=1;j<=n;j++)
      if(a[j][i]>0) ans[i]=a[j][n+1]^a[j][i];
 return res;
}
int main(){
    int T,n,num;
 scanf("%d",&T);
 while(T--){
      scanf("%d",&n);
         for(int i=1;i<=n;i++)
    scanf("%d",&f[i]);
   for(int i=1;i<=n;i++)
    scanf("%d",&e[i]);
         memset(G,0,sizeof(G));
   int x,y;
   while(scanf("%d%d",&x,&y)==2){
        if(x==0&&y==0) break;
     G[y][x]=1;
   }
   for(int i=1;i<=n;i++){
        G[i][n+1]=f[i]^e[i];
     G[i][i]=1;
   }
   num=Gauss(G,l,ans,n);
   bool flag=true;
   for(int i=n;i>n-num;i--)
    if(G[i][n+1]!=0){
     printf("Oh,it's impossible~!!\n");
     flag=false;
        break;
    }
   if(flag){
       printf("%d\n",1<<num);
   }
 }
 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值