POJ-1830

开关问题

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 6294   Accepted: 2393

Description

有 N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关 的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一 次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)

Input

输入第一行有一个数K,表示以下有K组测试数据。
每组测试数据的格式如下:

第一行 一个数N(0 < N < 29)

第二行 N个0或者1的数,表示开始时N个开关状态。

第三行 N个0或者1的数,表示操作结束后N个开关的状态。

接下来 每行两个数I J,表示如果操作第 I 个开关,第J个开关的状态也会变化。每组数据以 0 0 结束。

Output

如果有可行方法,输出总数,否则输出“Oh,it‘s impossible~!!” 不包括引号

Sample Input

2
3
0 0 0
1 1 1
1 2
1 3
2 1
2 3
3 1
3 2
0 0
3
0 0 0
1 0 1
1 2
2 1
0 0

Sample Output

4
Oh,it‘s impossible~!!

Hint

第一组数据的说明:
一共以下四种方法:

操作开关1

操作开关2

操作开关3

操作开关1、2、3 (不记顺序)

/**
          题意:给一些开关,开某一个开关之后有的开关也会变化
          做法:高斯消元  线性代数
**/
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#define maxn 50
using namespace std;
int mmap[maxn][maxn];
int start[maxn];
int eed[maxn];
int guess(int equ,int val)
{
    int k=0,col = 0;
    int max_r = 0;
    for(k=0; k<equ&&col<val; k++,col++)
    {
        max_r = k;
        for(int i=k+1; i<equ; i++)
        {
            if(abs(mmap[i][col]) > abs(mmap[max_r][col]))
            {
                max_r = i;
            }
        }
        if(max_r != k)
        {
            for(int i=k; i<val+1; i++)
            {
                swap(mmap[k][i],mmap[max_r][i]);
            }
        }
        if(mmap[k][col] == 0)
        {
            k--;
            continue;
        }
        for(int i=k+1; i<equ; i++)
        {
            if(mmap[i][col] != 0)
            {
                for(int j=col; j<val+1; j++)
                {
                    mmap[i][j] ^= mmap[k][j];
                }
            }
        }
    }
    ///上三角
    for(int i=k; i<equ; i++)
    {
        if(mmap[i][col]!=0) return -1;
    }
    return val-k;
}
int main()
{
//#ifndef ONLINE_JUDGE
//    freopen("in.txt","r",stdin);
//#endif // ONLINE_JUDGE
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        memset(start,0,sizeof(start));
        memset(eed,0,sizeof(eed));
        for(int i=0; i<n; i++)
        {
            scanf("%d",&start[i]);
        }
        for(int i=0; i<n; i++)
        {
            scanf("%d",&eed[i]);
        }
        int u,v;
        memset(mmap,0,sizeof(mmap));
        while(scanf("%d %d",&u,&v))
        {
            if(u == 0 && v == 0) break;
            u--;
            v--;
            mmap[v][u] = 1;
        }
        for(int i=0; i<n; i++)
        {
            mmap[i][i] = 1;
        }
        for(int i=0; i<n; i++)
        {
            mmap[i][n] = start[i]^eed[i];
        }
        int res = guess(n,n);
        if(res == -1) printf("Oh,it‘s impossible~!!\n");
        else printf("%d\n",1<<res);
    }
    return 0;
}
时间: 2024-12-14 08:58:25

POJ-1830的相关文章

POJ 1830 开关问题

简单的高斯消元取模,答案为2^自由变元的数量,但是题目的意思把I,J搞反了,坑爹... 开关问题 Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 5425   Accepted: 2023 Description 有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开.你的目标是经过若干次

poj 1830 开关问题 高斯消元

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

POJ 1830 【高斯消元第一题】

首先...使用abs()等数学函数的时候,浮点数用#include<cmath>,其它用#include<cstdlib>. 概念: [矩阵的秩] 在线性代数中,一个矩阵A的列秩是A的线性无关的纵列的极大数目.类似地,行秩是A的线性无关的横行的极大数目. 此题如果有解,解的个数便是2^(自由变元个数),因为每个变元都有两种选择,既1 << n 对于r以下的行,必定全是0,那么如果a[i][n]!=0 必然出现矛盾,于是判定无解. 1 #include <iostr

Poj 1830 高斯消元

开关问题 Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 5418 Accepted: 2022 Description 有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开.你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态.对于任意一个开关,最多只能进行一次开关操作.你的任

POJ 1830 开关问题 高斯消元,自由变量个数

http://poj.org/problem?id=1830 如果开关s1操作一次,则会有s1(记住自己也会变).和s1连接的开关都会做一次操作. 那么设矩阵a[i][j]表示按下了开关j,开关i会被操作一次,记得a[i][i] = 1是必须的,因为开关i操作一次,本身肯定会变化一次. 所以有n个开关,就有n条方程, 每个开关的操作次数总和是:a[i][1] + a[i][2] + ... + a[i][n] 那么sum % 2就代表它的状态,需要和(en[i] - be[i] + 2) % 2

数学 --- 高斯消元 POJ 1830

开关问题 Problem's Link: http://poj.org/problem?id=1830 Mean: 略 analyse: 略增广矩阵:con[i][j]:若操作j,i的状态改变则con[i][j]=1,否则con[i][j]=0. 最后的增广矩阵应该是N*(N+1),最后一列:对比开光的始末状态,若相同则为0,若不同则为1: 最后的解共有三种:1.无解,既出现了一行中前面N个数为0,第N+1的值非0:2.没有第1种情况出现,存在X行数值全为0,则解的个数为2^X;3,没有1,2

【POJ 1830】 开关问题

[题目链接] http://poj.org/problem?id=1830 [算法] 列出异或方程组,用高斯消元求解 [代码] #include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio

poj 1830 高斯消元

终于会一点高斯消元了,认真学还是学的进去啊...... 搞明白解异或方程的原理,然后构造出矩阵就好做了.模板题 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <stack> 5 #include <queue> 6 #include <map> 7 #include <algorithm> 8 #include <v

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

题目链接 Solutin: 将每个开关使用的情况当成未知数,如果开关i能影响到开关j,那么系数矩阵A[j][i]的系数为1. 每个开关增广矩阵的值是开关k的初状态异或开关k的目标状态,这个应该很容易想到. 方程都列好了,直接消元就好了. code /* 解异或方程组 */ #include <iostream> #include <cstring> using namespace std; const int MAXN = 50; int prim[MAXN]; int A[MAX

poj 1830 开关问题 高斯消元法

开关问题 Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 5854   Accepted: 2213 Description 有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开.你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态.对于任意一个开关,最多只能进行一次开关操作