高斯消元练习题集

本文通过五个POJ题目详细讲解了高斯消元在开关问题和同余方程解算中的应用,包括EXTENDED LIGHTS OUT、Widget Factory、Painter’s Problem、SETI和Flip Game。每道题目的思路都涉及到异或运算下的高斯消元,以及扩展欧几里得解同余方程,有的还需要处理多解和无解的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.POJ-1222 EXTENDED LIGHTS OUT

题意
开关问题,给一个矩阵,每次翻转,上下左右都会一起翻转,问你翻转哪些位置,可以把灯全部关上。

思路

异或运算下的高斯消元

典型的开关问题,和 POJ 1830 开关问题 是一样的属于 XOR 类型的消元。

/***************************
*author:ccf
*source:poj-1222- EXTENDED LIGHTS OUT 
*topic:高斯消元
****************************/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;

const int N = 40;
const int inf = 50;
int cas,n,icas = 1;
int a[N][N];//增广矩阵
int equ,var;//equ:行     var: 列 
int free_i[N],free_cnt;
int x[N],mp[N];//x[N]自由元数组 

//void debug() {
   
//	for(int i = 0 ; i < equ; i++) {
   
//		for(int j = 0; j <= var; j++)
//			printf("%d ",a[i][j]);
//		printf("\n");
//	}
//
//}
bool Gauss() {
   
	int k,col,max_i;//k是列 col是行 max_i是最大行
	//转化为阶梯阵
	for(k = col = 0; k < equ && col < var; k++,col++) {
   
		//找到最大行
		max_i = k;
		for(int i = k + 1; i < equ; i++) {
   
			if(abs(a[i][col]) > abs(a[max_i][col])) max_i = i;
		}
		if(a[max_i][col] == 0) {
   
			free_i[col] = 1;
			x[free_cnt++] = col;
			k--;
			continue;
		}
		if(k != max_i) {
   
			for(int j = col; j <= var; j++) {
   
				swap(a[max_i][j],a[k][j]);
			}
		}
		//开始化简阶梯阵
		for(int i = 0; i < equ; i++) {
   
			if(a[i][col] && i != k)
				for(int j = col; j <= var; j++)
					a[i][j] ^= a[k][j];
		}
	}
	//debug();
	for(int i = k; i < equ; i++) 
		if(a[i][var]) return false;
	return true;
}
int main() {
   
	//freopen("date.in","r",stdin);
	equ = var = 30;
	scanf("%d",&cas);
	while(cas--) {
   
		int cnt = 0;
		memset(a,0,sizeof(a));
		memset(free_i,0,sizeof(free_i));
		memset(x,0,sizeof(x));
		memset(mp,0,sizeof(mp));
		for(int i = 0; i < equ; i++) {
   
			scanf("%d",&mp[i]);
			a[i][var] = mp[i];
		}
		//方格化成增广矩阵
		for(int i = 0 ; i < equ; i++) {
   
			a[i][i] = 1;
			if(i < 24) a[i][i+6] = 1;
			if(i > 5) a[i][i-6] = 1;
			if(i % 6 != 0) a[i][i-1] = 1;
			if(i % 6 != 5) a[i][i+1] = 1;
		}

		if(!Gauss()) printf("no solution!\n");
		else {
   
			printf("PUZZLE #%d\n",icas++);
			for(int i = 1; i <= 30; i++) {
   
				printf("%d",a[i-1][var]);
				if(i % 6 == 0) printf("\n");
				else printf(" ");
			}
		}
	}
	return 0;
}
2.POJ-2947-Widget Factory

题意
有n种饰品,每种的加工时间为3~9天,现在知道m条记录,每条记录形如:开始时间是周几,终止时间是周几,加工出来哪些饰品,各多少件。但是不知道持续了多少周。
求每种饰品的加工时间。

需要判断无解和多解。
思路

高斯消元解同余方程

在原本高斯约旦消元的基础上,加上取模的运算,最后每一行得到一个
A x ≡ C ( m o d p ) Ax\equiv C(mod p) AxC(modp)形式的式子,使用扩展欧几里得解同余方程即可,也有直接模拟取余操作的方法。

/***********************
*author:ccf
*source:poj-2974 Widget Factory
*topic:高斯消元解同余方程
************************/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;

const int N = 600;
int cas,n,m,icas;
char start[5],fired[5];
int a[N][N],ans[N];//行列式  解集
int equ,var,free_cnt = 0;

void debug() {
   
	for(int i = 1; i <= equ; i++) {
   
		for(int j = 1; j <= var + 1; j++) {
   
			printf("%d ",a[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}
int sti(char *s) {
   
	if(strcmp(s, "MON") == 0) return 1;
	else if(strcmp(s, "TUE") == 0) return 2;
	else if
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值