POJ 1830 开关问题(高斯消元法)

题意:给出初始状态,结束状态,以及灯之间的相护关联性,求有多少种开灯方式,满足初始到结束状态的转换

思路:这是一个裸的高斯消元的问题,对应题意输入,构造好增广矩阵就可以了。

也是做的第一个高斯消元的问题,算是理解了高斯消元,

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define maxn 35

int x[maxn];
int a[maxn][maxn];
int w[maxn][maxn];                    //w[i][j] 表示 i,j是否能互相影响

int gcd(int z,int y)
{
    if(y==0) return z;
    return gcd(y,z%y);
}
int abs(int z)
{
    if(z>=0) return z;
    return -z;
}
void swap(int i,int j,int m){
    int t;
    for(int k=i;k<m;k++)
        t=w[i][k],w[i][k]=w[j][k],w[j][k]=t;
}

void Xor(int i,int j,int m){
    for(int k=i;k<=m;k++)
        w[j][k]=w[j][k]^w[i][k];
}

void print(int n,int m){
    for(int i=0;i<n;i++){
        for(int j=0;j<m+1;j++)
            printf("%d ",w[i][j]);
        printf("\n");
    }
    printf("\n\n");
}

int gauss(int n,int m){                        //高斯消元 解 异或方程
    //print();
    int lie=0,i;
    for(i=0;i<n&&lie<m;i++,lie++)
    {
        int maxx=i;
        for(int j=i+1;j<n;j++)
        {
            if(abs(w[j][lie])>abs(w[maxx][lie]))
                maxx=j;
        }
        if(maxx!=i)
        {
            swap(i,maxx,m+1);
        }
        if(w[i][lie]==0)
        {
            i--;
            continue;
        }
        for(int j=i+1;j<n;j++)
        {
            if(w[j][lie])
            {
                int z=gcd(abs(w[j][lie]),abs(w[i][lie]));
                int zz=abs(w[j][lie])*abs(w[i][lie])/z;
                int xa=zz/abs(w[j][lie]),xb=zz/abs(w[i][lie]);
                if(w[j][lie]*w[i][lie]<0)
                    xb=-xb;
                for(int k=lie;k<m+1;k++)
                {
                    w[j][k]=(w[j][k]*xa-w[i][k]*xb+2)%2;
                }
            }
        }
    }
        for(int j=i;j<n;j++)
        {
            if(w[j][lie]) return -1;
        }
        if(i<n) return n-i;
        for(int j=n-1;j>=0;j--)
        {
            int temp=w[j][n-1]%2;
            for(int k=j+1;k<n;k++)
            {
                if(w[j][k])
                    temp=(temp-w[j][k]*x[k]%2+2)%2;
                if(temp%w[j][j])
                    return -2;
                x[j]=temp/w[j][j]%2;
            }
        }
        return 0;
}
int n,m;
int T,cnt;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        cnt++;
        scanf("%d",&n);
        m=n;
        memset(w,0,sizeof(w));
        memset(x,0,sizeof(x));
        for(int i=0;i<n;i++)
            w[i][i]=1;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&w[i][n]);
        }
        int x,y;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            w[i][n]^=x;
        }

        while(~scanf("%d%d",&x,&y))
        {
            if(x==0&&y==0) break;
            w[y-1][x-1]=1;
        }
        int z=gauss(n,m);
        if(z==-1) printf("Oh,it's impossible~!!\n");
        else printf("%d\n",1<<z);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值