zoukankan      html  css  js  c++  java
  • P1275 魔板

    题目描述

    有这样一种魔板:它是一个长方形的面板,被划分成n行m列的n*m个方格。每个方格内有一个小灯泡,灯泡的状态有两种(亮或暗)。我们可以通过若干操作使魔板从一个状态改变为另一个状态。操作的方式有两种:

    (1)任选一行,改变该行中所有灯泡的状态,即亮的变暗、暗的变亮;

    (2)任选两列,交换其位置。

    当然并不是任意的两种状态都可以通过若干操作来实现互相转化的。

    你的任务就是根据给定两个魔板状态,判断两个状态能否互相转化。

    输入输出格式

    输入格式:

    文件中包含多组数据。第一行一个整数k,表示有k组数据。

    每组数据的第一行两个整数n和m。(0<n,m≤100)

    以下的n行描述第一个魔板。每行有m个数字(0或1),中间用空格分隔。若第x行的第y个数字为0,则表示魔板的第x行y列的灯泡为“亮”;否则为“暗”。

    然后的n行描述第二个魔板。数据格式同上。

    任意两组数据间没有空行。

    输出格式:

    共k行,依次描述每一组数据的结果。

    若两个魔板可以相互转化,则输出YES,否则输出NO。(注意:请使用大写字母)

    输入输出样例

    输入样例#1: 
    2
    3 4
    0 1 0 1
    1 0 0 1
    0 0 0 0
    0 1 0 1
    1 1 0 0
    0 0 0 0
    2 2
    0 0
    0 1
    1 1
    1 1
    输出样例#1: 
    YES
    NO
    

    Solution:

      本题其实没有想象的那么难(主要是我开始受到刚做的另一道叫魔板的题目影响,下意识的想怎么去判重存状态去了,结果感觉不可做),实际上直接暴力模拟就可以了。

      首先可以确定的是无论怎么操作,每一行的$1$的个数都只有两种情况(要么是本来的$1$的个数,要么是$0$的个数),所以操作$1$对于每行来说最多进行一次,当行中的$0,1$都确定不变后,那么要使初始状态$st$变换到目标状态$ed$就是操作$2$了。

      于是一个很简单的思路就出来了:

      1、先判断$st$的每行$1$的个数是否可以变到$ed$中的每行$1$的个数,若不行直接输出$NO$,可以变换再枚举。

      2、首先枚举$st$的每一列来做为转移时中间状态的第$1$列,通过操作$1$使得其和目标状态的第$1$列相同,之后就只需用到操作$2$,依次枚举剩下的列中和目标状态第$2$列、第$3$列…一直往下(记得当两列相同后,要在中间状态中通过操作$2$移动该列到匹配的位置,否则往后枚举可能会出现列重复使用的情况),当某列无法和目标状态匹配时,直接跳出循环,说明该中间状态不行。

      具体实现,详见代码。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long 
    using namespace std;
    const int N=105;
    int st[N][N],ed[N][N],tmp[N][N],n,m,k,hang1[N],hang2[N];
    bool vis[N],f,hang[N],lie[N];
    il int gi(){
        int a=0;char x=getchar();bool f=0;
        while((x<'0'||x>'9')&&x!='-')x=getchar();
        if(x=='-')x=getchar(),f=1;
        while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
        return f?-a:a;
    }
    il void change1(int x[][N],int k){
        for(int i=1;i<=m;i++)x[k][i]=1-x[k][i];
    }
    il void change2(int x[][N],int s,int t){
        for(int i=1;i<=n;i++)swap(x[i][s],x[i][t]);
    }
    il bool check(int s[][N],int t[][N],int l1,int l2){
        for(int i=1;i<=n;i++)
            if(s[i][l1]!=t[i][l2])return 0;
        return 1;
    }
    il void init(){
        n=gi(),m=gi();f=0;
        memset(hang1,0,sizeof(hang1));
        memset(hang2,0,sizeof(hang2));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
            st[i][j]=gi();
            if(st[i][j]==1)hang1[i]++;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
            ed[i][j]=gi();
            if(ed[i][j]==1)hang2[i]++;
            }
            if(hang1[i]!=hang2[i]&&hang1[i]!=m-hang2[i])f=1;
        }
        if(f){puts("NO");return;}
        for(int p=2;p<=m;p++){
            memcpy(tmp,st,sizeof(st));
            change2(tmp,1,p);
            for(int i=1;i<=n;i++)
                if(tmp[i][1]!=ed[i][1])change1(tmp,i);
            for(int i=1;i<=m;i++){
                f=0;
                for(int j=i;j<=m;j++)
                if(check(tmp,ed,j,i)){change2(tmp,i,j);f=1;break;}
                if(!f)break;
            }
            if(f)break;
        }
        if(f){puts("YES");return;}
        puts("NO");
    }
    int main(){
        k=gi();
        while(k--){
            init();
        }
        return 0;
    }
  • 相关阅读:
    Effective C++_笔记_条款00_基本术语
    SVM(三)—Kernels(核函数)
    SVM(支持向量机)(二)—Lagrange Duality(拉格朗日对偶问题)
    Logistic Regression(逻辑回归)(二)—深入理解
    java程序验证用户名密码和验证码登录的小例子
    java连接MySQL数据库并读取内容
    一个简单的模板了解css+div网页布局
    HTML文件中css样式的引用
    慕课笔记利用css进行布局【混合布局练习】
    慕课笔记利用css进行布局【混合布局】
  • 原文地址:https://www.cnblogs.com/five20/p/8909094.html
Copyright © 2011-2022 走看看