蛇形填数&开灯问题 精讲

暑期集训已经开始两天了,有种被拖着跑的感觉,我感觉自己的基础太差了,有些简单的动态规划,能听懂,思路也不难,就是自己打的时候,全是bug,连深搜,广搜的算法都需要看一两天才能明白具体的内容,究其根本还是打的代码太少,所以我觉得自己还是应该从基本的编程基础开始,在刷题中,巩固境界,一点点的进步,毕竟每个人的情况不一样嘛。
蛇形填数
给定一个 n , 在 n * n 的方阵中填入 1 ,2, 3,……,n * n, 要求填成蛇形。

例如在 n = 5 时 , 如下所示:

13 14 15 16 1

12 23 24 17 2

11 22 25 18 3

10 21 20 19 4

9 8 7 6 5

思路:
设置一个二维数组, 以 x 代表行, y 代表列
填数的顺序是 下, 左, 上, 右
直到一个方向无法再填数时,再进行下一个方向的填数

#include<bits/stdc++.h>
#include<iostream>
#define max 20 //max的值不能太大,否则程序无法运行 
using namespace std;
int main()
{
	int n,x,y;
	cin >> n;
	x=0;
	y=n-1;
	int a[max][max];
	memset(a,0,sizeof(a));//及时的初始化 
	int top=0;
	top=a[x][y] = 1;//也可以赋值到这里面。 
	while(top<n*n)//不超过最大值,同时注意不要++放前面和后面的用法 
	{
		
		while(x+1<n && !a[x+1][y])  a[++x][y] = ++top;//从最外面先向下 
		while(y-1>=0 && !a[x][y-1])  a[x][--y] = ++top;//再往 左 
		while(x-1>=0 && !a[x-1][y])  a[--x][y] = ++top;//再往上 
		while(y+1<n && !a[x][y+1])  a[x][++y] = ++top;// 再往右
		//学会如何去用坐标控制方向,在bfs,dfs算法中也用的上,!a[x+1][y]表示,超过格子范围的数不存在 
	}
	for(x=0;x<n;x++)
	{
			for(y=0;y<n;y++)
		{
			printf("%3d",a[x][y]);//这样使打印的矩阵排列整齐 
		}
		cout<<endl;
	}
	
	return 0;
}

开灯问题
n盏灯,编号为1-n,第一个人把所有灯打开,第二个人按下所有编号两倍的开关(这些灯被关掉),第三个人按下所有编号三倍的开关,以此类推,一共有k个人,问最后有哪些灯开着?

输入:n和k,输出开着的灯的编号,k<=n<=1000

样例输入:

7 3

样例输出:

1 5 6 7

算法思路:

其实我们可以采用数组存储多少盏灯的状态,然后模拟接下来的人开关灯的操作,怎么模拟?比如我们设置两个循环,第一个循环是操作的人,第二个循环是对所有的灯循环,通过第二个循环中我们拿每一盏灯的序号来和第几个人操作的来进行取余运算,如果为0,则模拟开关灯操作,就是将数组的值取相反值即可。

#include
#include
#include
using namespace std;
int num[1001]; //定义一个数组,保存灯的状态0为关闭,1为打开

int main()
{
memset(num,0,sizeof(num)); //给数组初始化全部为0
int n,k;
cin>>n>>k;//代表灯的个数和人的人数
int flag = 1; //这个flag标识变量是用来判断输出是否为第一个 ,节省多出来的空格

	for(int i = 1;i<=k;i++){  			// 这两个循环是模拟开关灯操作 
		for(int j = 1;j<=n;j++){		//第一个循环是代表开关灯的倍数,第二个循环是判断开关灯状态以及修改操作 
			if(j%i == 0) num[j] = !num[j];//相当于赋值为一,注意这个循环的过程
		}
	} 
	
	for(int i = 1;i<=100;i++){
	if(num[i]){
		if(flag) flag = 0;    //这个是判断输出是否为第一个,是一个输出的技巧避免多出一个空格 
		else cout<<" ";
		cout<<i; 
	} 	
	}
	cout<<endl;
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值