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相等。就是操作次数的奇偶性要相等。

那么来一个高斯消元,就知道是否有可能有解。

在有解的情况下,可能存在自由变量,什么意思呢?

就是假设有k个自由变量,那么就是前n - k个变量有固定的操作,使得能变成最终结果,那么这k个自由变量就可以任取值了,一共有2^k种不同的取值方案。因为方案不要求有顺序,所以那个灯取那个状态,都是相同的一种解。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 1e2 + 20;
class GaussMatrix {  //复杂度O(n3)
public:
    int a[maxn][maxn];
    int equ, val; //方程(行)个数,和变量(列)个数,其中第val个是b值,不能取
    void init() {
        for (int i = 1; i <= equ; ++i) {
            for (int j = 1; j <= val; ++j) {
                a[i][j] = 0;
            }
        }
    }
    void swapRow(int rowOne, int rowTwo) {
        for (int i = 1; i <= val; ++i) {
            swap(a[rowOne][i], a[rowTwo][i]);
        }
    }
    void swapCol(int colOne, int colTwo) {
        for (int i = 1; i <= equ; ++i) {
            swap(a[i][colOne], a[i][colTwo]);
        }
    }
//    bool same(double x, double y) {
//        return fabs(x - y) < eps;
//    }
    int guass() {
        int k, col; // col,当前要处理的列, k当前处理的行
        for (k = 1, col = 1; k <= equ && col < val; ++k, ++col) { //col不能取到第val个
            int maxRow = k; //选出列最大值所在的行,这样使得误差最小。(没懂)
            for (int i = k + 1; i <= equ; ++i) {
                if (abs(a[i][col]) > abs(a[maxRow][col])) {
                    maxRow = i;
                }
            }
            if (a[maxRow][col] == 0) { //如果在第k行以后,整一列都是0
                --k; //则这个变量就是一个自由变量。
                continue;
            }
            if (maxRow != k) swapRow(k, maxRow); // k是当前的最大行了
            for (int i = col + 1; i <= val; ++i) { //整一列约去系数
                a[k][i] /= a[k][col];
            }
            a[k][col] = 1; //第一个就要变成1了,然后它下面和上面的变成0
            for (int i = 1; i <= equ; ++i) {
                if (i == k) continue; //当前这行,不操作
                for (int j = col + 1; j <= val; ++j) {
                    a[i][j] = (a[i][j] - a[i][col] * a[k][j] + 2) % 2;
                }
                a[i][col] = 0;
            }
//            debug();
        }
        for (int res = k; res <= equ; ++res) {
            if (a[res][val] != 0) return -1; //方程无解
        }
        return val - k; //自由变量个数
    }
    void debug() {
        for (int i = 1; i <= equ; ++i) {
            for (int j = 1; j <= val; ++j) {
                cout << a[i][j] << " ";
            }
            printf("\n");
        }
        printf("*******************************************\n\n");
    }
}arr;
int be[maxn], en[maxn];
void work() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> be[i];
    for (int i = 1; i <= n; ++i) cin >> en[i];
    arr.init();
//    memset(&arr, 0, sizeof arr);
    arr.equ = n, arr.val = n + 1;
    do {
        int x, y;
        cin >> x >> y;
        if (x == 0 && y == 0) break;
        arr.a[x][x] = 1;
        arr.a[y][x] = 1;
    } while (true);
    for (int i = 1; i <= n; ++i) {
        arr.a[i][n + 1] = (en[i] - be[i] + 2) % 2;
        arr.a[i][i] = 1; //这个是必须的。
    }
//    arr.debug();
    int res = arr.guass();
    if (res == -1) {
        cout << "Oh,it‘s impossible~!!" << endl;
    } else cout << (1 << res) << endl;
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    int t;
    cin >> t;
    while (t--) work();
    return 0;
}

时间: 2024-12-04 18:15:37

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

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

[ACM] POJ 2947 Widget Factory (高斯消元)

Widget Factory Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 4436   Accepted: 1502 Description The widget factory produces several different kinds of widgets. Each widget is carefully built by a skilled widgeteer. The time required to

POJ 1166 The Clocks 高斯消元 + exgcd(纯属瞎搞)

根据题意可构造出方程组,方程组的每个方程格式均为:C1*x1 + C2*x2 + ...... + C9*x9 = sum + 4*ki; 高斯消元构造上三角矩阵,以最后一个一行为例: C*x9 = sum + 4*k,exgcd求出符合范围的x9,其他方程在代入已知的变量后格式亦如此. 第一发Gauss,蛮激动的. #include <algorithm> #include <iostream> #include <cstring> #include <cstd

POJ - 1222: EXTENDED LIGHTS OUT (开关问题-高斯消元)

pro:给定5*6的灯的状态,如果我们按下一个灯的开关,它和周围4个都会改变状态.求一种合法状态,使得终状态全为关闭: sol:模2意义下的高斯消元. 终于自己手打了一个初级板子. #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; int a[40][40],ans[40]; int x[5]={0,0,0,1,-1}; int y[5]={0,1,-1,0,0};

poj 2947 Widget Factory (高斯消元,解模线性方程)

链接:poj 2947 题意:生产一些零件,已知零件种数,记录条数 记录只记录了某次生产从周几开始,周几结束,以及生产了哪些产品. 每件商品生产所需天数为3-9天. 求每样产品需要多少天才能完成. 若无解输出Inconsistent data. 有无穷解输出Multiple solutions. 有唯一解,输出其解 分析:根据题目所给信息,可以列出同余方程组,再根据高斯消元求解, 但还得判断是无解,无穷解,还是唯一解 1.系数矩阵的秩若与增广矩阵的秩不相等,则无解,否则有解 2.若有解,若增广矩

poj 2947 Widget Factory(高斯消元)

description The widget factory produces several different kinds of widgets. Each widget is carefully built by a skilled widgeteer. The time required to build a widget depends on its type: the simple widgets need only 3 days, but the most complex ones

【POJ1830】开关问题 高斯消元求自由元

#include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/43482357"); } 题意:中文题. 题解: 呃,求自由元个数,然后输出1<<ans:(自由元就是高斯消元消某个变量x时发现以下所有方程当前此位系数都是0) 如果无解输出那个题中给的串. 诶网上代码真不可看,我绝望了决定照自己

POJ 2065 SETI(高斯消元解模方程组)

题目: SETI Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 1693   Accepted: 1054 Description For some years, quite a lot of work has been put into listening to electromagnetic radio signals received from space, in order to understand what

POJ - 1830:开关问题 (开关问题-高斯消元-自由元)

pro:有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开.你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态.对于任意一个开关,最多只能进行一次开关操作.你的任务是,计算有多少种可以达到指定状态的方法.(不计开关操作的顺序) sol:即求自由元的个数,答案是pow(2,自由元). #include<bits/stdc++.h> #defin