高斯消元求解线性方程组_POJ1830_开关问题

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/85911285

点此打开题目页面

思路分析: 

     设a_{ij}\in {0, 1}, x_{i}\in {0, 1},1 \leq i \leq N, 1\leq j\leq N, 当且仅当按开关j开关i的状态改变时a_{ij}=1, 否则a_{ij}=0, 如果按开关i则x_{i}=1

, 否则x_{i}=0, b_{i}为开关的初始状态, {b_{i}}'为开关i的目标状态, XOR表示异或运算, 可得如下方程组:

    a_{11}x_{1}XOR....a_{1n}x_{n}=b_{1}XOR{b_{1}}'

    ....

    a_{n1}x_{1}XOR....a_{nn}x_{n}=b_{n}XOR{b_{n}}'

    如果上述方程组无解,  则方案数为0, 如果有唯一解则方案数为1,  如果自由元个数为k(k\geq 1)个,  则方案数为2^{k}个(因为x_{i}只能为0或1)

    具体实现见如下AC代码:

//POJ1830_开关问题
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX = 100;
int N, a[MAX];//a[i]:增广矩阵第i行
int main(){
	int K; scanf("%d", &K);
	while(K--){
		scanf("%d", &N);
		memset(a, 0, sizeof(a));
		for(int i = 1; i <= N; ++i) scanf("%d", &a[i]);
		for(int i = 1; i <= N; ++i){
			int y; scanf("%d", &y), a[i] ^= y;
			a[i] |= 1 << i;//a[i][i]为1 
		}
		int u, v;
		while(scanf("%d %d", &u, &v), u && v) a[v] |= 1 << u;
		int res = 1;
		//开始高斯消元
		for(int i = 1; i <= N; ++i){
			for(int j = i; j <= N; ++j) if(a[i] < a[j]) swap(a[i], a[j]);
			if(!a[i]){
				res = 1 << N - i + 1; break;
			}
			if(a[i] == 1){
				res = 0; break;
			}
			//查找a[i]最高位的1, 然后消元 
			for(int j = N; j >= 1; --j)
				if(a[i] >> j & 1){
					for(int k = 1; k <= N; ++k){
						if(i == k) continue;
						if(a[k] >> j & 1) a[k] ^= a[i];
					}
					break;	
				}
		} 
		if(!res) cout << "Oh,it's impossible~!!" << endl;
		else cout << res << endl;
	}
	return 0;
} 
扫描二维码关注公众号,回复: 4797670 查看本文章

猜你喜欢

转载自blog.csdn.net/solider98/article/details/85911285