2011-08-09 07:59:50Morris

b099. E. 聯立多元一次方程式 (優化重製)

b099. E. 聯立多元一次方程式

內容 :

在我們所學過的數學知識中,下面兩個二元一次方程式並沒有什麼不同:

5X + 4Y = 9                            0.000001X + 8Y = 8

0.000001X + 8Y = 8                       5X + 4Y = 9

這兩組聯立二元一次方程式所得到的解應該是一樣的(直觀地來看,應該非常接近於X=1, Y=1),遺憾的是我們眼前的這部電子計算機,並不這麼認為。事實上,利用電腦來計算含有浮點數的問題常常會引發各式各樣的誤差,大多時候這些誤差是可以非常渺小到我們所無法感覺,但很多時候這些誤差會使得電腦解出我們想都想不到的答案。解聯立多元一次方程式就是一個很好的例子。

重新來複習一下,所謂N元一次方程式是如下列的N組方程式:

A11X1 + A12X2 + A13X3 + … + A1NXN = B1

A21X1 + A22X2 + A23X3 + … + A2NXN = B2

A31X1 + A32X2 + A33X3 + … + A3NXN = B3

.

.

.

AN1X1 + AN2X2 + AN3X3 + … + ANNXN = BN

如果代入N=2,就是形成如下所示的二元一次方程式:

A11X1 + A12X2 = B1

A21X1 + A22X2 = B2

當然平時我們習慣以下面的符號來表示它:

AX + BY = C

DX + EY = F

不過事實上它們代表著同樣一件事。

隨著工程問題日益複雜與龐大,使用電子計算機來求解大型的聯立方程式(實際地說,N從數百到數千的範圍)是勢在必行的,然而浮點數運算上的問題卻又常常困擾著我們;這裡,我們需要你的幫助。

5 X + 4Y = 9                       0.00001X + 8Y = 8

0.00001X + 8 Y = 8                   5X + 4Y = 9

我們說左邊這組二元一次方程式是比較「優質」的方程組,是因為它是一個「對角線主導」(diagonal dominate)的方程組,也就是說在對角線上的兩個係數58都是同一個方程式的係數絕對值中最大的(5 > 4, 8 > 0.00001)

在三元一次方程組中一個對角線主導的例子:

8X + 2Y + Z = 7                 (8 > 2, 8 > 1)

4X – 6Y  + Z = 10              (6 > 4, 6 > 1)

-2X – 3Y – 7Z = 0                (7 > 2, 7 > 3)

我們發現,上面這個方程組不但是對角線主導,它還有更好的性質。就是對角線上的元素不但是同方程式中絕對值最大的係數,它甚至大於其他係數絕對值的總和:(8>1+2, 6>1+4, 7>2+3),我們稱這是一個「強對角線主導」的方程組。

有數學家幫我們證明了,強對角線主導的方程組用計算機做運算必定可以達到高精準的結果,現在必須要請求你的幫忙,能否寫一個程式,對於一給定的N元一次聯立方程組,判斷該方程組是否能經由「改變方程式間的順序」來形成一個「強對角線主導」的方程組。

輸入說明 :

輸入檔的第一行是一個正整數T (1 ≤ T ≤ 50),表輸入檔中共有T個多元一次方程組。每個方程組的第一行是一個正整數N (2 ≤ N ≤ 1000),表示一個N元一次方程組。接下來的N行每行會恰有N個數(可能含有小數),第i行的第j個數表示N元一次方程組中的係數Aij(小數點後至多給至六位數字且-999.999999 ≤ Aij ≤ 999.999999),任兩個正整數間以恰一個空白字元隔開。B的值本題不需要考慮。

輸出說明 :

輸出應包含T行,第i行是表示第i個方程組能否調換順序形成強對角線主導的方程組。若是,請輸出yes,反之請輸出no

範例輸入 :

4
2
5 4
0.000001 8
2
0.000001 8
5 4
3
8 2 1
4 -6 1
-2 -3 -7
3
8 2 1
4 -6 1
-2 -3 -4

範例輸出 :

yes
yes
yes
no

提示 :

出處 :

2005 NPSC 國中組初賽


C語言基礎優化版本
/**********************************************************************************/
/*  Problem: b099 "E. 聯立多元一次方程式" from 2005 NPSC 國中組初賽 */
/*  Language: C                                                                   */
/*  Result: AC (136ms, 196KB) on ZeroJudge                                        */
/*  Author: morris1028 at 2011-08-05 20:27:29                                     */
/**********************************************************************************/


#include<stdio.h>        
#include<stdlib.h>
double ReadPoint() {
    static char c;
    int p = 0;
    double t = 1;
    while((c = getchar()) >= '0')
        t /= 10, p = (p << 3) + (p << 1) + (c-'0');
    return (double)p*t;
}
int ReadDouble(double *x) {
    static char c, neg;
    while((c = getchar()) < '-')    {if(c == EOF) return EOF;}
    if(c == '.')    {*x = ReadPoint();return 0;}
    neg = (c == '-') ? -1 : 1;
    *x = (neg == 1) ? c-'0' : 0;
    while((c = getchar()) >= '0')
        *x = (*x)*10 + c-'0';
    if(c == '.')    *x += ReadPoint();
    *x *= neg;
    return 0;

main() {
    int t, n, maxflag;     
    double sum, max, m;
    while(scanf("%d", &t) == 1) {     
        int a, b, c, flag;     
        while(t--) {
            scanf("%d", &n);  
             flag = 1;
            int x[1000] = {0};
            for(a = 0; a < n; a++) {
                sum = 0, max = -1;
                for(b = 0; b < n; b++)  {
                    ReadDouble(&m);
                     if(m < 0) m *= -1;  
                    sum += m;
                    if(m > max)
                        max = m, maxflag = b;
                }
                sum -= max;
                if(sum >= max) flag = 0;
                if(flag != 0) {
                    if(x[maxflag]) flag = 0;
                    else x[maxflag] = 1;
                }
              }
            puts(flag ? "yes" : "no");
        }
    }
    return 0;
}

C++ 極端優化版本
/**********************************************************************************/

/*  Problem: b099 "E. 聯立多元一次方程式" from 2005 NPSC 國中組初賽 */
/*  Language: CPP                                                                 */
/*  Result: AC (70ms, 1706KB) on ZeroJudge                                        */
/*  Author: morris1028 at 2011-08-05 20:31:09                                     */
/**********************************************************************************/


#include<stdio.h>         
#include<stdlib.h>
inline int readchar() {
    const int N = 1048576;
    static char buf[N];
    static char *p = buf, *end = buf;
    if(p == end) {
        if((end = buf + fread(buf, 1, N, stdin)) == buf) return EOF;
        p = buf;
    }
    return *p++;
}
inline double ReadPoint() {
    static char c;
    int p = 0;
    double t = 1;
    while((c = readchar()) >= '0')
        t /= 10, p = (p << 3) + (p << 1) + (c-'0');
    return (double)p*t;
}
inline int ReadDouble(double *x) {
    static char c, neg;
    while((c = readchar()) < '-')    {if(c == EOF) return EOF;}
    if(c == '.')    {*x = ReadPoint();return 0;}
    neg = (c == '-') ? -1 : 1;
    *x = (neg == 1) ? c-'0' : 0;
    while((c = readchar()) >= '0')
        *x = (*x)*10 + c-'0';
    if(c == '.')    *x += ReadPoint();
    *x *= neg;
    return 0;
}  
inline int ReadInt(int *x) {
    static char c, neg;
    while((c = readchar()) < '-')    {if(c == EOF) return EOF;}
    neg = (c == '-') ? -1 : 1;
    *x = (neg == 1) ? c-'0' : 0;
    while((c = readchar()) >= '0')
        *x = (*x << 3) + (*x << 1) + c-'0';
    *x *= neg;
    return 1;
}
main() {
    int t, n, maxflag;      
    double sum, max, m;
    while(ReadInt(&t) != EOF) {
        int a, b, c, flag;      
        while(t--) {
            ReadInt(&n);
             flag = 1;
            int x[1000] = {0};
            for(a = 0; a < n; a++) {
                sum = 0, max = -1;
                for(b = 0; b < n; b++)  {
                    ReadDouble(&m);
                     if(m < 0) m *= -1;   
                    sum += m;
                    if(m > max)
                        max = m, maxflag = b;
                }
                sum -= max;
                if(sum >= max) flag = 0;
                if(flag) {
                    if(x[maxflag]) flag = 0;
                    else x[maxflag] = 1;
                }
              }
            puts(flag ? "yes" : "no");
        }
    }
    return 0;
}