您的位置:首页 > 其它

pku 1222 EXTENDED LIGHTS OUT 解题报告 之高斯消去法

2009-10-24 13:40 561 查看
pku 1222 EXTENDED LIGHTS OUT 解题报告 之高斯消去法
之前我写了这题的解题报告,但并不是最优化的方法。有点像模拟的那种。还好,经过算法导论这个群上的牛人指导,现在我终于可以用到了最优的方法——高斯消去法。十分感谢那位牛人。年龄还比我小呢。要加油才行。感觉数学很强,很中用。自己在大一并没有疯狂学好数学,现在可真后悔。
思路:首先我应该想想,press一次(i,j)的灯,影响其上下左右的灯,这就好比就相当于对整个灯盘做了一次线性变换。想明白这一点十分重要(相信你能想明白~~~~(*^__^*) 嘻嘻……)~。那么我们就可以将结果30个假设为30个未知量x。输入的灯初始状态作为线性方程组右端的30个值,那么其线性方程组左端的系数怎么求呢?其实我已经说了,当press一次(i,j)的灯,相当于一次线性变换,那么求出每个灯翻转一次,受影响的灯,即其他xi值,变换得:x1+···+xi=ans(i)。
想明白这个数学模型,问题就很好解决。剩下就是套用高斯消去法的模板了。但要注意一点就是结果要%2。
AC代码:

#include <iostream>

using namespace std;
#define N 30
bool fr
;
int f

, ans
, x
, n, t;
int dr[4] = {-1, 1, 0, 0};
int dc[4] = {0, 0, -1, 1};
void set(int i, int r, int c)
{
int j = r * 6 + c;
f[i][j] = 1;
}
void init()
{
int r, c;
memset(f, 0, sizeof(f));
for (int i = 0; i < n; i++)
{ //第i块影响哪些
r = i / 6, c = i % 6;
set(i, r, c);
if (r > 0)
{
set(i, r + dr[0], c + dc[0]);
}
if (r < 4)
{
set(i, r + dr[1], c + dc[1]);
}
if (c > 0)
{
set(i, r + dr[2], c + dc[2]);
}
if (c < 5)
{
set(i, r + dr[3], c + dc[3]);
}
}
}
int Guass()
{
int t, i, j, k, temp;
bool flag;
for (t = 0; t < n; t++)
{
if (f[t][t] == 0)
{
flag = false;
for (i = t + 1; i < n; i++)
{
if (f[i][t] != 0)
{
flag = true;
for (k = 0; k < n; k++)
{
temp = f[t][k];
f[t][k] = f[i][k];
f[i][k] = temp;
}
temp = ans[t];
ans[t] = ans[i];
ans[i] = temp;
break;
}
}
if (!flag)
{
return 1;
}
}
for (i = t + 1; i < n; i++)
{
if (f[i][t] != 0)
{
temp = f[i][t];
for (j = t; j < n; j++)
{
f[i][j] = (f[i][j] * f[t][t]) % 2;
f[i][j] = (f[i][j] - f[t][j] * temp + 2) % 2;
}
ans[i] = (ans[i] * f[t][t] - ans[t] * temp + 2) % 2;
}
}
}
for (i = n - 1; i >= 0; i--)
{
temp = ans[i];
for (j = n - 1; j > i; j--)
{
temp = (temp - f[i][j] * x[j] + 2) % 2;
}
x[i] = ((temp / f[i][i]) + 2) % 2;
}
return 0;
}
void print()
{
for (int i = 0; i < n; i++)
{
int t = i % 6;
if (t)
{
printf(" ");
}
printf("%d", x[i]);
if (t == 5)
{
printf("/n");
}
}
}
int main()
{
scanf("%d",&t);
for (int q = 1; q <= t; q++)
{
n = 30;
for (int i = 0; i < n; i++)
{
scanf("%d", ans + i);
}
init();
printf("PUZZLE #%d/n",q);
Guass();
print();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: