C语言枚举法解决熄灯问题&&memcpy函数

有一个由按钮组成的矩阵,每行6个,共5行,每个按钮控制一盏灯

按下一个按钮,该按钮(上下左右)的灯都会改变状态,即灭变亮,亮变灭。

现在要使得所有灯熄灭,给出解决方案。

文章目录

一、输入&&输出

1.输入

第一行是一个正整数,表示需要解决的案例数目

每个案例由5行6列组成,以空格隔开,

0-->灭,1-->亮

2.输出

对每个案例先输出一行"PUZZLE#m",m是该案例的序号

5行6列,空格隔开

0-->需要按下对应按钮

1-->不需要按下

二、分析&&代码

1.分析

角上改变三盏灯

边上改变四盏灯

其它改变五盏灯

按两次等于没按,每个按钮最多按1次

第一行的状态确定的话,其他的也就有不多的几种情况

要灭第一行第i列亮的灯,就要按下第2行第i列的开关

2.代码

#include <stdio.h>
#include <string.h>
int GetBit(char c,int i);
void SetBit(char *c,int i,int v);
void FlipBit(char *c,int i);
void OutputResult(int t,char result[]);
char  orilights[5];
char   lights[5];//变化中的矩阵的灯的状态
char   result[5];
void main()
{
	int T;
	printf("请输入组数T:\n");
    scanf("%d",&T);
    for(int t=1;t<=T;t++)
	{printf("请输入灯的状态:\n");
		for(int i=0;i<5;i++)
		{
			for(int j=0;j<6;j++)
			{
			//把原始的灯的矩阵读进来,放到orilights中
				int s;
				scanf("%d",&s);
				//s是第i行第j列的灯的状态,0或1
				SetBit(&orilights[i],j,s);
			}
		}
		for(int n=0;n<64;n++)
		{    //枚举第一行的情况
			//每个n代表第一行的灯的状态
			int switchs=n;//switchs代表当前行的灯的状态
            //处理每一行的情况
			memcpy(lights,orilights,sizeof(orilights));
			for (int i=0;i<5;i++)
			{   //第i行的开关状态已经确定,就是switchs
			   // 每一行的开关状态存在result[i]中
				result[i]=switchs;
               //让第i行的开关起作用,
				//首先让它影响第i行的灯。
				for(int j=0;j<6;j++)
				{
                    if(GetBit(switchs,j))
					{//对同一行的灯进行处理
                        if(j>0)
							FlipBit(&lights[i],j-1);
						//灯的状态放在lights中
                         FlipBit(&lights[i],j);
						 if(j<5)
							 FlipBit(&lights[i],j+1);
					}
				}
				if(i<5)
				{//处理第i+1行的情况
					lights[i+1]^=switchs;
					//switchs代表第i行的开关状态
				}
				switchs=lights[i];
			}//确保前四行的开关都是灭的
			//最后一行的开关状态放在lights[4]中
			if(lights[4]==0)
			{
				//第5行都是灭的,成功了
				OutputResult(t,result);
				break;
			}
		}
	}
}
int GetBit(char c,int i)
{   //取字符c的第i个bit
	return (c>>i)&1;
	//c右移i位,c的第i位就跑到了第0位
}
void SetBit(char *c,int i,int v)
{
	//设置c的第i位为v
    if(v==1)
	{
    	*c|=(1<<i);//c的第i位变成了1
	}
	else 
		*c&=~(1<<i);//(1<<i)是只有第i位为1,其它位都为0
	              //c第i位为0,其它位不变
}
void FlipBit(char *c,int i)
{
	//将c的第i位翻转,1变成0,0变成1
	*c^=(1<<i);
}
void OutputResult(int t,char result[])
{
    printf("PUZZLE #%d\n",t);
	for(int i=0;i<5;i++)
	{
		for(int j=0;j<6;j++)
		{
			printf("%d",GetBit(result[i],j));
			if(j<5)
				printf(" ");
		}
		printf("\n");
	}
}

3.运行结果 

请输入组数T:
1
请输入灯的状态:
0 1 1 0 1 0
1 0 0 1 0 0
0 1 1 0 1 1
1 0 0 1 1 1
0 0 0 1 1 0
PUZZLE #1
1 0 0 1 1 1
1 0 0 0 0 0
1 1 0 0 1 1
1 1 0 1 1 1
0 1 0 1 1 0
Press any key to continue

 


三.memcpy函数

函数原型

void *memcpy(void *destin, void *source, unsigned n);

参数

  • destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。

  • source-- 指向要复制的数据源,类型强制转换为 void* 指针。

  • n-- 要被复制的字节数。

返回值

该函数返回一个指向目标存储区destin的指针。

功能

从源source所指的内存地址的起始位置开始拷贝n个字节到目标destin所指的内存地址的起始位置中。 [2] 

所需头文件

C语言:#include<string.h>

C++:#include<cstring>

应用说明

1.source和destin所指的内存区域可能重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前不被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向destin的指针。

2.如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。

注意:source和destin都不一定是数组,任意的可读写的空间均可。

区别

strcpy和memcpy主要有以下3方面的区别。

1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。

3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值