POJ 1222 EXTENDED LIGHTS OUT (高斯消元)

题目链接

题意:5*6矩阵中有30个灯,操作一个灯,周围的上下左右四个灯会发生相应变化 即由灭变亮,由亮变灭,如何操作使灯全灭?

题解:这个问题是很经典的高斯消元问题。同一个按钮最多只能被按一次,因为按两次跟没有按是一样的效果。那么 对于每一个灯,用1表示按,0表示没有按,那么每个灯的状态的取值只能是01。列出30个方程,30个变元,高斯消元解出即可。打表观察我们可以发现5*6的矩阵是一定有解的,主对角线元素都是1所以一定有唯一解

打表代码:

 

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;
char s[300][300];
int g[300][300],ans[300];//注意这里定义的大小是n^2 不是n
int dir[5][2]= {{0,0},{0,1},{0,-1},{1,0},{-1,0}};
int n,m1,m2;
int gauss()
{
    int row,col;
    for(row=0,col=0; row<n&&col<n; col++) //注意是小于n
    {
        int id=row;
        for(int i=row+1; i<n; i++)
            if(g[i][col]) id=i;
        if(g[id][col])
        {
            for(int k=col; k<=n; k++)
                swap(g[id][k],g[row][k]);//注意这里是k
            for(int j=row+1; j<n; j++)
                if(g[j][col])
                    for(int k=col; k<=n; k++) //注意这里每段代码的特点 一点都不能写错
                        g[j][k]^=g[row][k];
            row++;//一定注意这句话放到if里
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        printf("%d ",g[i][j]);
        printf("   *******\n");
    }
//    for(int i=row; i<n; i++)
//        if(g[i][n]) return -1;
//    int ans=0;
//    for(int i=n-1; i>=0; i--)
//    {
//        for(int j=n-1; j>i; j--)
//            g[i][n]^=g[i][j]&&g[j][n];
//        ans+=g[i][n];
//    }
//    return ans;
    return -1;
}
int main()
{

    m1=5;m2=6;
    n=m1*m2;
    //1
    memset(g,0,sizeof(g));
    for(int i=0; i<m1; i++)
        for(int j=0; j<m2; j++)
            for(int k=0; k<5; k++)
            {
                int a=i+dir[k][0];
                int b=j+dir[k][1];
                if(a>=0&&b>=0&&a<m1&&b<m2)
                    g[a*m2+b][i*m2+j]=1; //注意这里是 *m2, 模拟几个数就能理解了
            }
    int ans1,ans2;
    ans1=gauss();
    return 0;
}

 

 

 

AC代码:

 

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;
int n=30;
int f[35][35];
int g[35][35];
int dir[5][2]= {{0,0},{0,1},{1,0},{-1,0},{0,-1}};
void input()
{
    for(int i=0; i<30; i++)
        scanf("%d",&g[i][30]);
}
void work()
{
    int row,col;
    for(row=0,col=0; row<n&&col<n; col++)
    {
        int id=row;
        for(int i=id; i<n; i++)
            if(g[i][col])
                id=i;
        if(g[id][col])
        {
            for(int k=col; k<=n; k++)
                swap(g[row][k],g[id][k]);
            for(int i=row+1; i<n; i++)
                if(g[i][col])
                    for(int k=col; k<=n; k++)
                        g[i][k]^=g[row][k];
            row++;
        }
    }
    //构建上三角完毕 下面开始回代过程
    for(int i=n-1;i>=0;i--)
    for(int j=n-1;j>i;j--)
    g[i][30]^=g[i][j]&&g[j][30];
    //这一行可以参考传统的求解过程来理解
}
void print()
{
    for(int i=0; i<30; i++)
    {
        if((i+1)%6!=0)
            printf("%d ",g[i][30]);
        else
            printf("%d\n",g[i][30]);
    }
}
void debug()
{
    for (int i =0; i <30; i++)
    {
        for (int j =0; j <31; j++)
            cout <<""<< g[i][j];
        cout << endl;
    }
    cout << endl;
}
int main()
{
    for(int i=0; i<5; i++)
        for(int j=0; j<6; j++)
            for(int k=0; k<5; k++)
            {
                int a=i+dir[k][0];
                int b=j+dir[k][1];
                if(a>=0&&b>=0&&a<5&&b<6)
                    f[i*6+j][a*6+b]=1;
            }
    int t,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        printf("PUZZLE #%d\n",cas++);
        memcpy(g,f,sizeof(g));
        input();
        work();
        print();
    }
    return 0;
}

 

posted @ 2016-09-03 14:15  Ritchie丶  阅读(134)  评论(0编辑  收藏  举报