POJ 1222 (开关问题+高斯消元法)

题目链接http://poj.org/problem?id=1222

题目大意:一堆开关,或开或关。每个开关按下后,周围4个方向开关反转。问使最后所有开关都关闭的,开关按法。0表示不按,1表示按。

解题思路

一共只有5*6个开关。

对于每个开关,设其最终状态为x5,上下左右四个开关最终状态分别为x1,x2,x3,x4,

那么有方程x1^x2^x3^x4^x5^初始状态=0。

这样就有30个方程。解这30个线性方程组即可。

用高斯消元法来解方程组,变化如下:

①对于原本找列中绝对值最大这一步,可以简化成找第一个为1的k,因为系数矩阵不是0就是1,最大就是1。

②原本的+号现在变成^号。

这里推荐一下cxlove神牛的简洁写法,他把col和row合二而一,又将解向量和系数矩阵合二为一,非常吊。

 

#include "cstdio"
#include "iostream"
using namespace std;
int ratio[31][31],dir[5][2]={0,0,-1,0,1,0,0,-1,0,1};
void reset()
{
    for(int i=0; i<5; i++)
        for(int j=0; j<6; j++)
            for(int k=0; k<5; k++)
            {
                int x=i+dir[k][0],y=j+dir[k][1];
                if (x>=0&&y>=0&&x<5&&y<6) ratio[i*6+j][x*6+y]=1;
            }
}
void guess()
{
    for(int i=0;i<30;i++)
    {
        int k=i;
        for(;k<30;k++)
            if(ratio[k][i]!=0) break;
        for(int j=0;j<=30;j++) swap(ratio[i][j],ratio[k][j]);
        for(int j=0;j<30;j++)
        {
            if(i!=j&&ratio[j][i])
                for(int k=0;k<=30;k++)
                   ratio[j][k]=ratio[i][k]^ratio[j][k];
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int T,no=0;
    scanf("%d",&T);
    while(T--)
    {
        printf("PUZZLE #%d
",++no);
        reset();
        for(int i=0;i<30;i++) scanf("%d",&ratio[i][30]);
        guess();
        for(int i=0;i<30;i++)
        {
            printf("%d",ratio[i][30]);
            if(i%6==5) printf("
");
            else printf(" ");
        }

    }
}
13596495 neopenx 1222 Accepted 160K 0MS C++ 1186B 2014-11-04 00:51:23

 

 

原文地址:https://www.cnblogs.com/neopenx/p/4072623.html