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");
}
}
}