zoukankan      html  css  js  c++  java
  • [openjudge 1813] 熄灯问题 2017-05-10 19:27 89人阅读 评论(1) 收藏

    openjudge 1813 熄灯问题

    描述
    有一个由按钮组成的矩阵,其中每行有6个按钮,共5行。每个按钮的位置上有一盏灯。当按下一个按钮后,该按钮以及周围位置(上边、下边、左边、右边)的灯都会改变一次。即,如果灯原来是点亮的,就会被熄灭;如果灯原来是熄灭的,则会被点亮。在矩阵角上的按钮改变3盏灯的状态;在矩阵边上的按钮改变4盏灯的状态;其他的按钮改变5盏灯的状态。

    在上图中,左边矩阵中用X标记的按钮表示被按下,右边的矩阵表示灯状态的改变。对矩阵中的每盏灯设置一个初始状态。请你按按钮,直至每一盏等都熄灭。与一盏灯毗邻的多个按钮被按下时,一个操作会抵消另一次操作的结果。在下图中,第2行第3、5列的按钮都被按下,因此第2行、第4列的灯的状态就不改变。
    这里写图片描述
    请你写一个程序,确定需要按下哪些按钮,恰好使得所有的灯都熄灭。根据上面的规则,我们知道1)第2次按下同一个按钮时,将抵消第1次按下时所产生的结果。因此,每个按钮最多只需要按下一次;2)各个按钮被按下的顺序对最终的结果没有影响;3)对第1行中每盏点亮的灯,按下第2行对应的按钮,就可以熄灭第1行的全部灯。如此重复下去,可以熄灭第1、2、3、4行的全部灯。同样,按下第1、2、3、4、5列的按钮,可以熄灭前5列的灯。
    这里写图片描述

    输入
    5行组成,每一行包括6个数字(0或1)。相邻两个数字之间用单个空格隔开。0表示灯的初始状态是熄灭的,1表示灯的初始状态是点亮的。
    输出
    5行组成,每一行包括6个数字(0或1)。相邻两个数字之间用单个空格隔开。其中的1表示需要把对应的按钮按下,0则表示不需要按对应的按钮。
    样例输入
    0 1 1 0 1 0
    1 0 0 1 1 1
    0 0 1 0 0 1
    1 0 0 1 0 1
    0 1 1 1 0 0
    样例输出
    1 0 1 0 0 1
    1 1 0 1 0 1
    0 0 1 0 1 1
    1 0 0 1 0 0
    0 1 0 0 0 0
    来源
    1222

    题解

    枚举第一行熄灯的情况

    如果上一行是1,则下一行是1

    例:100101 下一行也是 100101 就可以关上一行的灯
    这样推出后面几行

    最后对最后一行进行判断

    如果最后一行都是0就找到了答案 下面是代码

    使用dfs搜索第一行的情况

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    bool a[10][10];//a记录开关灯情况
    bool k[10][10];//原有的开关灯情况
    bool c[10][10];//答案数组
    void turn(int x,int y){//开关灯的函数
        a[x][y]=!a[x][y];
        if(x>=2) a[x-1][y]=!a[x-1][y];
        if(x<=4) a[x+1][y]=!a[x+1][y];
        if(y>=2) a[x][y-1]=!a[x][y-1];
        if(y<=5) a[x][y+1]=!a[x][y+1];
    }
    bool pd(){//判断是否成功关完
        for(int i=1;i<=6;i++)
            if(a[5][i]==1)
            return false;
        return true;
    }
    void deal(){//开关灯
        for(int i=1;i<=6;i++){
            if(c[1][i]==1)
            turn(1,i);
        }
        for(int i=2;i<=5;i++)
        {
            for(int j=1;j<=6;j++)
            if(a[i-1][j]==1)
            {
                c[i][j]=1;
                turn(i,j);
            }
        }
    }
    void makea(){//用a记下k
        for(int i=1;i<=5;i++)
            for(int j=1;j<=6;j++)
                a[i][j]=k[i][j];
    }
    void clean(){//如果失败 将c清零
        for(int i=2;i<=5;i++)
        for(int j=1;j<=6;j++){
            c[i][j]=0;
        }
    }
    bool flag=0;//判断是否成功
    void dfs(int step){//搜索出c[1]的情况
        if(!flag){//成功就退出
            if(step==7){//找出一种c[1]就进行判断
                clean();//清空c
                makea();//用a记下k
                deal();//开关灯
                if(pd()){
                    flag=1;
                }
                return;
            }
            for(int i=0;i<=1;i++)
            {
                c[1][step]=i;
                dfs(step+1);
                if(flag==1) return ;//成功就退出
            }
        }
    }
    int main()
    {
        for(int i=1;i<=5;i++)
            for(int j=1;j<=6;j++)
                scanf("%d",&k[i][j]);
        dfs(1);//从1开始
        for(int i=1;i<=5;i++){//输出
            for(int j=1;j<=6;j++)
                cout<<c[i][j]<<" ";
            cout<<endl;
        }
        return 0;
    }
    

    update 2017 .6 .29

    回档第一篇博客 又是一种心情

    觉得那个时候好辣鸡的啊
    连个dfs都想半天
    学了高斯消元以后 重新来做此题 又花了好长时间(我是制杖吗?。。)
    嗯 高斯消元的做法
    首先:
    1.这个点按奇数次和按一次是一样的 按偶数次和不按是一样的 因为按两次就又回去了
    2.按的顺序和答案没有关系
    列方程:
    一个点最多被五个点影响(上下左右+自己) 因为每个点的次数只是0或者1 所以首先得到方程
    像这个样子x1+x2+x3+x4+x5(mp[i][j]指i,j是否要改变)
    但是mod2不是很好处理了
    又想到 1和 1 变0 0和1 变1 那么这个时候用异或运算就好

    x1^x2^x3^x4^x5=mp[i][j]
    那么 此题是5*6的格子 需要30个未知数 列30个方程 解一下就行

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int n=5,m=6;int cnt=30;
    int mp[50][50];
    int a[50][50];
    int dx[10]={0,1,-1,0,0};
    int dy[10]={0,0,0,1,-1};
    void gauss(){
        for(int i=1;i<=30;i++){
            int k=i;
            for(;k<=30;k++)
                if(a[k][i]!=0) break;
            swap(a[i],a[k]);
            for(int p=1;p<=30;p++){
                if(p!=i&&a[p][i])
                {
                    for(int j=i;j<=31;j++)
                        a[p][j]=a[p][j]^a[i][j];//异或方程 
                }
            }
        }
    }
    int mk(int x,int y){
        return (x-1)*6+y;
    }
    bool in_Map(int x,int y){
        if(x<1||x>n||y<1||y>m) return false;
        return true;
    }
    void build(){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                int plc=mk(i,j);
                a[plc][31]=mp[i][j];//要得到的答案即要改变此点的次数 
                a[plc][plc]=1;
                for(int k=1;k<=4;k++){
                    int tx=i+dx[k];
                    int ty=j+dy[k];
                    if(!in_Map(tx,ty)) continue;
                    a[plc][mk(tx,ty)]=1;
                }
            }
    }
    int main(){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&mp[i][j]);
        build();
        gauss();
        int cnt=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
                printf("%d ",a[++cnt][31]);
            printf("
    ");
        }
        return 0;
    }
    

    附:poj1222=此题
    代码如下咯:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int n=5,m=6;int cnt=30;
    int mp[50][50];
    int a[50][50];
    int dx[10]={0,1,-1,0,0};
    int dy[10]={0,0,0,1,-1};
    void gauss(){
        for(int i=1;i<=30;i++){
            int k=i;
            for(;k<=30;k++)
                if(a[k][i]!=0) break;
            swap(a[i],a[k]);
            for(int p=1;p<=30;p++){
                if(p!=i&&a[p][i])
                {
                    for(int j=i;j<=31;j++)
                        a[p][j]=a[p][j]^a[i][j];//异或方程 
                }
            }
        }
    }
    int mk(int x,int y){
        return (x-1)*6+y;
    }
    bool in_Map(int x,int y){
        if(x<1||x>n||y<1||y>m) return false;
        return true;
    }
    void build(){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                int plc=mk(i,j);
                a[plc][31]=mp[i][j];//要得到的答案即要改变此点的次数 
                a[plc][plc]=1;
                for(int k=1;k<=4;k++){
                    int tx=i+dx[k];
                    int ty=j+dy[k];
                    if(!in_Map(tx,ty)) continue;
                    a[plc][mk(tx,ty)]=1;
                }
            }
    }
    int main(){
        int T;
        scanf("%d",&T);
        int nt=0;
        while(T--){
            printf("PUZZLE #%d
    ",++nt);  
            memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&mp[i][j]);
        build();
        gauss();
        int cnt=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
                printf("%d ",a[++cnt][31]);
            printf("
    ");
        }
    }
        return 0;
    }
    
  • 相关阅读:
    02-CSS基础与进阶-day4_2018-08-31-20-42-09
    02-CSS基础与进阶-day4__2018-08-31-20-22-57
    02-CSS基础与进阶-day3_2018-08-29-21-30-56
    02-CSS基础与进阶-day3_2018-08-29-20-39-58
    02-CSS基础与进阶-day3_2018-08-29-20-20-56
    02-CSS基础与进阶-day2_2018-08-27-22-00-56
    02-CSS基础与进阶-day2__2018-08-27-21-27-31
    02-CSS基础与进阶-day2_2018-08-27-20-57-55
    Pytest(12)pytest缓存
    Pytest(11)allure报告
  • 原文地址:https://www.cnblogs.com/xljxlj/p/7183674.html
Copyright © 2011-2022 走看看