您的位置:首页 > 其它

[高斯消元] poj 1222 EXTENDED LIGHTS OUT

2014-07-23 15:23 267 查看
题目大意:给你一个5*6的矩阵,矩阵里每一个单元都有一个灯和一个开关,如果按下此开关,那么开关所在位置的那个灯和开关前后左右的灯的状态都会改变(即由亮到不亮或由不亮到亮)。给你一个初始的灯的状态,问怎样控制每一个开关使得所有的灯最后全部熄灭(此题保证有唯一解)。

解题思路:高斯消元。很显然每个灯最多只需要按1下(因为按两下和没有按是一个效果)。我们可以定义30和未知数x0、x1.......x29代表每一个位置的开关是否被按。那么对于每一个灯的状态可以列一个方程,假设位置(i,j)处的开关为x(i*6+j),那么我们就可以列出方程:

x(i*6+j)+x((i-1)*6+j)+x((i+1)*6+j)+x(i*6+j-1)+x(i*6+j+1) = b(mod 2)

(括号里的数字为x的下标,这里假设这些下标都是符合要求的,即都在矩形内,如果不在则可以去掉,当这个灯初始时是开着的,那么bo为1,否则为0)

这样可以列出30个方程,然后用高斯消元解这个方程组即可。

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
int a[32][32];
void ok(int tep,int x,int y)
{
    if(x<0||y<0||x>=5||y>=6) return ;
    a[tep][x*6+y]=1;
    return ;
}
void gauss(int n,int m)          //高斯消元
{
    int i,j,k;
    for(i=0;i<n;i++)                          //逐行消元
    {
        for(k=i;k<n;k++) if(a[k][i]) break;      //对于当前行寻找对应列不为0的行
        for(j=0;j<m;j++) swap(a[i][j],a[k][j]);  //将其交换上来
        for(j=0;j<n;j++)                         //就此列对应的其他行消为0
        {
            if(i==j) continue;
            if(a[j][i])
            {
                for(k=0;k<m;k++)
                    a[j][k]^=a[i][k];
            }
        }
    }
}
int main()
{
    int t,cas=1;
    cin>>t;
    while(t--)
    {
        int i,j;
        for(i=0; i<5; i++)        //构造方程,也就是对于某个灯有几个开关能影响到
        {
            for(j=0; j<6; j++)
            {
                int tep=i*6+j;
                a[tep][tep]=1;
                ok(tep,i,j-1);
                ok(tep,i,j+1);
                ok(tep,i-1,j);
                ok(tep,i+1,j);
            }
        }
        for(i=0; i<30; i++)         // 对于某个灯,是需要按还是不需要按
            cin>>a[i][30];
        gauss(30,31);
        printf("PUZZLE #%d\n",cas++);
        for(i=0;i<30;i++)
        {
            if((i+1)%6==0) printf("%d\n",a[i][30]);
            else printf("%d ",a[i][30]);
        }
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: