POJ 1222
POJ 1222 结题报告(枚举和高斯)
这题可以用简单的方法求解,先穷举第一行的按键情况。然后一行一行关掉(做的时候看错题意,以为点亮,错了很久,所以一定要看清楚题意)前一排的灯。下面是代码,应该比较清晰。
#include <cstdio> #include <cstring> using std::memset; int mapback[5][6]; int map[5][6]; int press[5][6]; void flip(int i,int j) { map[i][j] = !map[i][j]; if(i > 0) map[i-1][j] = !map[i-1][j]; if(j > 0) map[i][j-1] = !map[i][j-1]; if(i < 4) map[i+1][j] = !map[i+1][j]; if(j < 5) map[i][j+1] = !map[i][j+1]; return; } void swapfirstrow(int swapkey) { int index = 0; while(swapkey) { if(swapkey%2) { press[0][index] = 1; flip(0,index); } swapkey /= 2; index++; } } bool solve() { for(int i = 1; i < 5; i++) { for(int j = 0 ; j < 6; j++) { if(map[i-1][j] == 1) { press[i][j] = 1; flip(i,j); } } } for(int i = 0 ; i < 6; i++) if(map[4][i] == 1) return false; return true; } void print() { for(int i = 0 ; i < 5; i++) { for(int j = 0 ; j < 5; j++) { printf("%d ", press[i][j]); } printf("%d\n", press[i][5]); } //printf("\n"); //for(int i = 0 ; i < 5; i++) //{ // for(int j = 0 ; j < 5; j++) // { // printf("%d ", map[i][j]); // } // printf("%d\n", map[i][5]); //} } int main() { int cas; scanf("%d", &cas); for(int casindex = 0 ; casindex < cas; casindex++) { for(int i = 0 ; i < 5; i++) { for(int j = 0 ; j < 6; j++) scanf("%d", &mapback[i][j]); } for(int i = 63 ; i >= 0; i--) { memcpy(map, mapback, sizeof(mapback)); memset(press, 0, sizeof(press)); swapfirstrow(i); if(solve()) { printf("PUZZLE #%d\n", casindex+1); print(); break; } } } }
下面会写下高斯消元的解法,详细思路可移步至 http://blog.csdn.net/shiren_Bod/article/details/5766907
注意的地方:
1. 矩阵中的乘法转换为^
2. 矩阵中的加法运算后mod2(结合性质“同一个位置翻两次等于不翻”)。
3. 注意guass消元中的细节问题,比如换行之后要将rowindex重置(在这份代码中rowindex表示当前操作行)。
4. 这个问题中不会出现多解(因为秩为30,discuss中有人说有多解。。),所以不用判断(rowindex !=-1)也行。
#include <cstdio> #include <cstring> using std::memset; const int MAX = 30; int map[MAX][MAX+1]; int ans[MAX]; void swap(int &a, int &b) { int t = a; a = b; b = t; return; } void guass(int nrows, int ncols) { for(int row = 0, col = 0 ; row < nrows && col < ncols; col++) { //deal with i th column //find the row; int rowindex = -1; for(int i = row ; i < nrows; i++) { if(map[i][col]) { rowindex = i; break; } } if(rowindex != -1){ //swap to this row if(rowindex != row) { for(int i = 0 ; i < ncols; i++) swap(map[row][i], map[rowindex][i]); } rowindex = row; //elimate the rows for(int i = 0; i < nrows; i++) { if(i != rowindex && map[i][col]) for(int j = col; j < ncols; j++) { map[i][j] ^= map[rowindex][j]; } } row++; } } //for(int i = 0 ; i < MAX; i++) //{ // for(int j = 0 ; j < MAX; j++) // printf("%d", map[i][j]); // printf(" %d\n", map[i][MAX]); //} //for(int i=0; i < MAX; i++) //求出结果; //{ // if(map[i][MAX]) // { // int j; // for(j=0; j<30 && !map[i][j]; j++) ; // if(j == 30) // return ; // else // ans[j] = map[i][30]; // } //} } int dx[5] = {0,0,0,1,-1}; int dy[5] = {0,1,-1,0,0}; int main() { int cas; scanf("%d", &cas); for(int casindex = 0 ; casindex < cas; casindex++) { memset(map, 0, sizeof(map)); memset(ans, 0, sizeof(ans)); for(int i = 0 ; i < MAX; i++) { int x = i/6; int y = i%6; for(int j = 0 ; j < 5; j++) { int x1 = x + dx[j]; int y1 = y + dy[j]; if(0 <= x1 && x1 < 5 && 0 <= y1 && y1 < 6) { map[i][x1*6+y1] = 1; } } } for(int i = 0 ; i < MAX; i++) scanf("%d", &map[i][MAX]); /*for(int i = 0 ; i < MAX; i++) { for(int j = 0 ; j < MAX; j++) printf("%d", map[i][j]); printf("\n"); }*/ guass(MAX, MAX+1); printf("PUZZLE #%d\n", casindex+1); for(int i = 0 ; i < 5; i++) { for(int j = 0 ; j < 6; j++) printf("%d ", map[i*6+j][MAX]); printf("\n"); } } }