POJ 1830 开关问题 高斯消元法
题意:N个开关,改变某开关,与此开关相关联的开关也会改变。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)
分析:第i个开关 ai1 * x1 + ai2 *x2 +...+ain*xn=bi , 其中当 开关 j 对 开关 i 有影响时,aij = 1,否则 aij = 0. 当开关i的状态改变时,bi = 1,否则bi = 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; }