您的位置:首页 > 其它

POJ 1830 开关问题 (高斯消元)

2013-10-31 19:15 381 查看
高斯消元分析

题意: 有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)

解法: 由开关之间的关联关系可建立n个方程,构成一个n阶增广矩阵,用高斯消元求解,若最后有k个自由元,则答案为2^k。时间复杂度为n^3。

/* Created Time: Thursday, October 31, 2013 PM06:37:21 CST */
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int M = 33;
int n,g[M][M];
int Gauss() {
int k,col;
for (k = 0,col = 0; k<n && col<n; k++,col++) {
int max_r = k;
for (int i = k+1; i < n; i ++)
if (g[i][col]>g[max_r][col]) max_r = i;
if (g[max_r][col]==0) {
k--;
continue;
}
if (max_r!=k)
for (int j = col; j <= n; j ++)
swap(g[k][j],g[max_r][j]);
for (int i = k+1; i < n; i ++)
if (g[i][col])
for (int j = col; j <= n; j ++)
g[i][j] ^= g[k][j];
}
for (int i = k; i < n; i ++)
if (g[i][col]) return -1;
return 1<<(n-k);
}
int main() {
int cas,a,b;
scanf("%d",&cas);
while (cas--) {
scanf("%d",&n);
memset(g,0,sizeof(g));
for (int i = 0; i < n; i ++)
scanf("%d",&g[i]
);
for (int i = 0; i < n; i ++) {
scanf("%d",&a);
g[i][i] = 1;
g[i]
^= a;
}
while (~scanf("%d%d",&a,&b),a||b)
g[b-1][a-1] = 1;
int ans = Gauss();
if (ans<0) puts("Oh,it's impossible~!!");
else printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: