1. 程式人生 > >POJ 1222 高斯消元更穩

POJ 1222 高斯消元更穩

ems 方程 pac wap 效果 row while 自由 方便

大致題意:

  有5*6個燈,每個燈只有亮和滅兩種狀態,分別用1和0表示。按下一盞燈的按鈕,這盞燈包括它周圍的四盞燈都會改變狀態,0變成1,1變成0。現在給出5*6的矩陣代表當前狀態,求一個能全部使燈滅的解。

分析:

  題目已經提示我們,按兩次和按零次是一樣的效果,所以每個燈的解為0或者1。這樣我們可以構造一個30*30的方程組,右邊的常數列為燈的初始狀態。

  影響當前燈的狀態的按鈕有5個

  a[i][j]+x[i][j]+x[i][j-1]+x[i-1][j]+x[i][j+1]+x[i][j+1]=0 (mod 2)

  x[i][j]+x[i][j-1]+x[i-1][j]+x[i][j+1]+x[i][j+1]=a[i][j] (mod 2)

  不難發現,燈的初始狀態只影響常數列,與系數矩陣無關,系數矩陣是不變的。

  消元的過程中系數也可以對2取模,按n次與按n+2次的效果是一樣的。對2取模更方便的運算就是異或了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

int n=30;
int a[35][35],x[35];
int mat[35][35];

void init()//初始化系數矩陣 { int dx[]= {0,0,-1,0,1}; int dy[]= {0,-1,0,1,0}; for(int i=1; i<=5; i++) { for(int j=1; j<=6; j++) { for(int k=0; k<5; k++) { int x=i+dx[k]; int y=j+dy[k]; if(x>0
&& x<=5 && y>0 && y<=6) mat[(i-1)*6+j][(x-1)*6+y]=1; } } } } void Gauss(int equ,int var) { int row,col; row=col=1; while(row<=equ && col<=var) { //列非零主 int r=row; for(int i=row; i<=equ; i++) if(a[i][col]!=0) { r=i; break; } if(r!=row) { for(int i=col; i<=var+1; i++) swap(a[row][i],a[r][i]); } if(a[row][col]==0)//說明有自由變元 { col++; continue; } //消元 for(int i=row+1; i<=equ; i++) { if(a[i][col]==0) continue; for(int j=col; j<=var+1; j++) a[i][j]^=a[row][j]; } row++; col++; } for(int i=equ; i>=1; i--) { x[i]=a[i][var+1]; for(int j=i+1; j<=var; j++) x[i]^=a[i][j]*x[j]; } } int main() { int t,kase=1; scanf("%d",&t); init(); while(t--) { memset(a,0,sizeof(a)); for(int i=1; i<=30; i++) scanf("%d",&a[i][31]); for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) a[i][j]=mat[i][j]; Gauss(n,n); printf("PUZZLE #%d\n",kase++); for(int i=1; i<=5; i++) { for(int j=1; j<6; j++) printf("%d ",x[(i-1)*6+j]); printf("%d\n",x[i*6]); } } return 0; }

POJ 1222 高斯消元更穩