zoukankan      html  css  js  c++  java
  • 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("
    ");
            }
            printf("*******************************************
    
    ");
        }
    }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;
    }
    View Code
  • 相关阅读:
    找到关注点
    c中printf必须在所有的变量申明之后才能用?
    在eclipse里面运行项目,并未出现中文乱码的问题;但是打成war包运行, tomcat运行startup.bat后控制台中文乱码
    《分工与贸易》笔记
    《范围:为什么通才能在专业化的世界中取胜》笔记
    《不充分均衡》笔记
    ”苦“没有价值
    《为什么佛学是真的》笔记
    《强力瞬间》笔记
    你和你的渴望
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6613673.html
Copyright © 2011-2022 走看看