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

本文介绍了解决POJ.1830开关问题的方法,使用高斯消元法求解异或方程组来计算开关操作的方案总数。详细解释了如何构建增广矩阵及普通矩阵,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ.1830 开关问题

标签(空格分隔): 高斯消元


题意分析

普通的高斯消元求解异或方程组,本题目要求的是输出总共的方案数目,若过没有则输出Oh,it’s impossible~!!。 主要学习一下a矩阵的构造。

首先说一下增广矩阵那部分,也就是常数项一部分。题目给出了每个开关起始状态和末了状态,根据这两个状态我们就可以判断出,具体某个开关是否应该被操作。打个比方,若一开始为1,最后为0,显然这个开关应该被按,一开始为0,最后也为0,那么这个开关就不能被按。可见是否按这个开关,结果应该是staiendi的值。

接着说普通矩阵那部分,首先按开关自身,开关本身应该发生变化,所以有 a[i][i]=1,然而题目中还有给出,按下某个开关x,另外一个开关y也会随之变化。换句话说,第y个开关的状态,受到开关x的影响,所以a[y][x]=1,在代码中,我是从0开始编号的,所以写的是a[y1][x1]=1

然后就可以直接跑高斯消元,最后输出i<<freeOfNum 即可;

代码总览

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define nmax 35
using namespace std;
int a[nmax][nmax];
int x[nmax];
int free_x[nmax];
int sta[nmax],ed[nmax];
int equ,var;
int Gauss(){
    int max_r;
    int col=0,num = 0;
    int k;
    for(int i = 0;i<=var;++i) x[i] = free_x[i] = 0;
    for(k = 0;k < equ && col < var;k++,col++){
        max_r=k;
        for(int i=k+1;i<equ;i++){
            if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
        }
        if(max_r!=k){
            for(int j=k ;j<var+1;j++) swap(a[k][j],a[max_r][j]);
        }
        if(a[k][col]==0){
            free_x[num++] = col;
            k--; continue;
        }
        for(int i=k+1;i<equ;i++){
            if(a[i][col]!=0){
                for(int j=col;j<var+1;j++){
                    a[i][j]^=a[k][j];;
                }
            }
        }
    }
    for(int i = k;i<equ;++i){
        if(a[i][col] != 0) return -1;
    }
    return var - k;
}

int main(){
    //freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&var);
        memset(a,0,sizeof a);
        equ = var;
        for(int i = 0 ;i<var;++i) scanf("%d",&sta[i]);
        for(int i = 0 ;i<var;++i) scanf("%d",&ed[i]);
        for(int i = 0 ;i<var;++i) a[i][var] = (sta[i] ^ ed[i]);
        for(int i = 0 ;i<var;++i) a[i][i] = 1;
        int x,y;
        while(scanf("%d %d",&x,&y)){
            if(x == 0 && y == 0) break;
            a[y-1][x-1] = 1;
        }
        int freeOfNum = Gauss();
        if(freeOfNum == -1) printf("Oh,it's impossible~!!\n");
        else{
            printf("%d\n",1<<freeOfNum);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值