POJ 1830 开关问题 高斯消元法

题意:N个开关,改变某开关,与此开关相关联的开关也会改变。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)

 

分析:第i个开关  ai1 * x+ ai2 *x2 +...+ain*xn=b, 其中当 开关 j 对 开关 i 有影响时,ai= 1,否则 aij = 0.   当开关i的状态改变时,b= 1,否则b= 0.

求自由变元的个数m,方法数为 2^m

 

 

const int maxn = 32;

int equ, var; // equ个方程 var个变元 增广阵行数为equ 分别为0到equ - 1 列数为var + 1 分别为0到var
int c[maxn][maxn], *a[maxn], x[maxn];//增广阵 行指针 解集
bool b[maxn]; // 判断是否是不确定的变元

void Debug(void){
    FOR(i, 0, equ) {
        FOR(j, 0, var + 1)
            cout << a[i][j] << " ";
        cout << endl;
    }
    cout << endl;
}

int gcd(int x, int y){
     if (!x || !y) return x + y;
     for (int t; t = x % y; x = y, y = t);
     return y;
}

int lcm(int x, int y) {
    return x * y / gcd(x, y);
}

void gauss(int &row, int &col){// 转换为阶梯阵
    for ( row = col = 0; row < equ && col < var; row++, col++) {
        int rmax = row;
        FOR (i, row + 1, equ) // 找绝对值最大的行
            if (abs(a[i][col]) > abs(a[rmax][col]))
                rmax = i;
        swap(a[row], a[rmax]); // 与当前行交换
        if (a[row][col] == 0) { row--; continue; }// 该col列全是0 处理下一列

        FOR (i, row + 1, equ)  // 枚举要删去的行
            if ( a[i][col] ) {
                int LCM = lcm( abs( a[i][col] ), abs( a[row][col] ) );
                int ta = LCM / abs( a[i][col] ), tb = LCM / abs( a[row][col] );
                //if ( a[i][col] * a[k][col] < 0 ) tb = -tb; // 异号的情况是两个数相加
                FOR (j, col, var + 1) {a[i][j] = a[i][j] * ta - a[row][j] * tb; a[i][j] &= 1;}
            }
    }
}

// -1无解 0唯一解 大于0无数解 并返回自由变元的个数
int Gauss() {                                                       //Debug();
    int row, col;
    gauss(row, col);// 转换为阶梯阵
                                                                    //Debug();
    FOR(i, row, equ) if(a[i][col]) return -1;// (0, ... ,0, a)无解
    if (row < var)return var - row;
    return 0;
}


int p[maxn],q[maxn];
void readdata(){
    //memset(b, -1, sizeof(b));
    memset(c, 0, sizeof c);
    scanf("%d", &equ); var = equ;               //cout<<equ<<endl;
    FOR(i, 0, equ) scanf("%d", &p[i]);
    FOR(i, 0, equ){
        a[i] = c[i];  a[i][i]=1;
        scanf("%d", &q[i]);
        if(p[i] != q[i]) a[i][var] = 1;
    }                              
    int u,v;
    while(scanf("%d%d",&u,&v),u){
        u--; v--;
        a[v][u] = 1;
    }
}

int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    #endif

    int k;
    scanf("%d",&k);
    while (k--) {
        readdata();
        int ans = Gauss();
        if (ans == -1) printf("Oh,it's impossible~!!\n");
        else printf("%d\n", 1<<ans);
    }
    return 0;
}

 

posted @ 2013-04-30 20:32  心向往之  阅读(157)  评论(0)    收藏  举报