poj 1830 高斯消元模版題

開關問題
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 6067 Accepted: 2309
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 (不記順序)
Source

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <cmath>
using namespace std;
const int maxn = 105;
int equ, var; // 有equ個方程,var個變元。增廣陣行數爲equ, 分別爲0到equ - 1,列數爲var + 1,分別爲0到var.
int a[maxn][maxn];
int x[maxn]; // 解集.
bool free_x[maxn]; // 判斷是否是不確定的變元.
int free_num;

void Debug(void)
{
    int i, j;
    for (i = 0; i < equ; i++)
    {
        for (j = 0; j < var + 1; j++)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}
inline int gcd(int a, int b)
{
    int t;
    while (b != 0)
    {
        t = b;
        b = a % b;
        a = t;
    }
    return a;
}
inline int lcm(int a, int b)
{
    return a * b / gcd(a, b);
}
// 高斯消元法解方程組(Gauss-Jordan elimination).(-2表示有浮點數解,但無整數解,-1表示無解,0表示唯一解,大於0表示無窮解,並返回自由變元的個數)
int Gauss(void)
{
    int i, j, k;
    int max_r; // 當前這列絕對值最大的行.
int col; // 當前處理的列.
    int ta, tb;
    int LCM;
    int temp;
    int free_x_num;
    int free_index;
    // 轉換爲階梯陣.
    col = 0; // 當前處理的列.
    for (k = 0; k < equ && col < var; k++, col++)
    { // 枚舉當前處理的行.
        // 找到該col列元素絕對值最大的那行與第k行交換.(爲了在除法時減小誤差)
        max_r = k;
        for (i = k + 1; i < equ; i++)
        {
            if (abs(a[i][col]) > abs(a[max_r][col])) max_r = i;
        }
        if (max_r != k)
        { // 與第k行交換.
            for (j = k; j < var + 1; j++) swap(a[k][j], a[max_r][j]);
        }
        if (a[k][col] == 0)
        { // 說明該col列第k行以下全是0了,則處理當前行的下一列.
            k--; continue;
        }
        for (i = k + 1; i < equ; i++)
        { // 枚舉要刪去的行.
            if (a[i][col] != 0)
    {
                LCM = lcm(abs(a[i][col]), abs(a[k][col]));
                ta = LCM / abs(a[i][col]), tb = LCM / abs(a[k][col]);
                if (a[i][col] * a[k][col] < 0) tb = -tb; // 異號的情況是兩個數相加.
                for (j = col; j < var + 1; j++)
                {
                    a[i][j] = a[i][j] * ta - a[k][j] * tb;
                }
    }
        }
    }
    //Debug();
    // 1. 無解的情況: 化簡的增廣陣中存在(0, 0, ..., a)這樣的行(a != 0).
    for (i = k; i < equ; i++)
    { // 對於無窮解來說,如果要判斷哪些是自由變元,那麼初等行變換中的交換就會影響,則要記錄交換.
        if (a[i][col] != 0) return -1;
    }
    // 2. 無窮解的情況: 在var * (var + 1)的增廣陣中出現(0, 0, ..., 0)這樣的行,即說明沒有形成嚴格的上三角陣.
    // 且出現的行數即爲自由變元的個數.
    if (k < var)
    {
        // 首先,自由變元有var - k個,即不確定的變元至少有var - k個.
        for (i = k - 1; i >= 0; i--)
        {
            // 第i行一定不會是(0, 0, ..., 0)的情況,因爲這樣的行是在第k行到第equ行.
            // 同樣,第i行一定不會是(0, 0, ..., a), a != 0的情況,這樣的無解的.
            free_x_num = 0; // 用於判斷該行中的不確定的變元的個數,如果超過1個,則無法求解,它們仍然爲不確定的變元.
            for (j = 0; j < var; j++)
            {
                if (a[i][j] != 0 && free_x[j]) free_x_num++, free_index = j;
            }
            if (free_x_num > 1) continue; // 無法求解出確定的變元.
            // 說明就只有一個不確定的變元free_index,那麼可以求解出該變元,且該變元是確定的.
            temp = a[i][var];
            for (j = 0; j < var; j++)
            {
                if (a[i][j] != 0 && j != free_index) temp -= a[i][j] * x[j];
            }
            x[free_index] = temp / a[i][free_index]; // 求出該變元.
            free_x[free_index] = 0; // 該變元是確定的.
        }
        return var - k; // 自由變元有var - k個.
    }
    // 3. 唯一解的情況: 在var * (var + 1)的增廣陣中形成嚴格的上三角陣.
    // 計算出Xn-1, Xn-2 ... X0.
    for (i = var - 1; i >= 0; i--)
    {
        temp = a[i][var];
        for (j = i + 1; j < var; j++)
        {
            if (a[i][j] != 0) temp -= a[i][j] * x[j];
        }
        if (temp % a[i][i] != 0) return -2; // 說明有浮點數解,但無整數解.
        x[i] = temp / a[i][i];
    }
return 0;
}

int main()
{
    //freopen("Input.txt", "r", stdin);
    int T;
    int s[101],e[101];
    cin>>T;
    while (T--)
    {
        int n,b,c;
        scanf("%d",&n);
        equ=n,var=n;
        for(int i=0;i<n;i++)scanf("%d",&s[i]);
        for(int i=0;i<n;i++)scanf("%d",&e[i]);


        memset(a, 0, sizeof(a));
        memset(x, 0, sizeof(x));
        memset(free_x, 1, sizeof(free_x)); // 一開始全是不確定的變元.

        for(int i=0;i<n;i++)
        {
           a[i][i]=1;
           a[i][n]=s[i]^e[i];
        }

        while(cin>>b>>c && (b||c)) a[c-1][b-1]=1;

        free_num = Gauss();
        if(free_num==-1)
           printf("Oh,it's impossible~!!\n");
        else
           printf("%d\n",1<<(free_num));
    }
    return 0;
}
發佈了244 篇原創文章 · 獲贊 17 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章