POJ 1830 开关问题 高斯消元,自由变量个数
Posted stupid_one
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于POJ 1830 开关问题 高斯消元,自由变量个数的主要内容,如果未能解决你的问题,请参考以下文章