C++基础算法:枚举

在这里插入图片描述

1.[P1003 NOIP 2011 提高组] 铺地毯 - 洛谷

image-20250310152202557

算法原理

枚举法:对于一些数据量较小的题目我们可以直接通过枚举出全部的结果,通过结果进行一一对比来判断结果是否正确叫做枚举法

这种方法的优势和劣势非常明显:虽然代码简单但是非常容易超时,后续我们可以通过一些手段进行优化

对于上述这道题我们可以直接通过将所有的数据全部列举到4个数组中,后直接将数组从后向前进行遍历并且一一比较即可

代码实现

#include <iostream>
using namespace std;
const int N = 1e4+10;
int a[N],b[N],c[N],d[N];

int main()
{
	int n; cin>>n;
	for(int i = 0;i<n;i++)
	{
		cin>>a[i]>>b[i]>>c[i]>>d[i];
	}
	int flag = 0;
	int x,y; cin>>x>>y;
	for(int i = n-1;i>=0;i--)
	{
		if(x>=a[i]&&x<=a[i]+c[i]&&y>=b[i]&&y<=b[i]+d[i])
		{
			flag = 1;
			cout<<i+1;
			break;
		}
	}
	if(flag == 0) cout<<-1;
}

2.[P2010 NOIP 2016 普及组] 回文日期 - 洛谷

image-20250310152420749

算法原理

这道题用一共可以有三种方式:

  1. 直接进行遍历,后直接比较(这种方式的时间复杂度是最大的)

    直接枚举,然后通过条件进行辨别,这里的时间复杂度太高就不进行代码提供了

  2. 将年份分离开来,通过枚举全部年份来确定回文数(这种时间复杂度较小于上面)

    这种方法有以下步骤:

    • 枚举年份,通过年份将月份和日用对应关系(/%)算出,如下:

      int main()
      {
      	int x,y; cin>>x>>y;
      	for(int i = 1;i<=9999;i++)
      	{
      		int month = i%10*10 + i/10%10;		
      		int day = i/100%10*10 + i/1000;
      		int k = i*10000+month*100+day;
      	}
      	return 0;
      }
      
    • 有年月后就可以判断这个月的天数,这里可以通过数组和函数实现

      static int GetMonthArray[] = {-1,31,28,31,30,31,30,31,31,30,31,30,31};
      int GetMonthDay(int year,int month)
      {
      	if(month==2&&((year%4==0&&year%100!=0)||year%400==0)) return 29;
      	else return GetMonthArray[month];
      }
      
  3. 仅仅枚举月日来确定回文数(这种时间复杂度为三者最小)

    和上面的代码相似

代码实现

方法二:

#include <iostream>
using namespace std;

static int GetMonthArray[] = {-1,31,28,31,30,31,30,31,31,30,31,30,31};
int GetMonthDay(int year,int month)
{
	if(month==2&&((year%4==0&&year%100!=0)||year%400==0)) return 29;
	else return GetMonthArray[month];
}

int main()
{
	int x,y; cin>>x>>y;
	int ret = 0;
	for(int i = 1;i<=9999;i++)
	{
		int month = i%10*10 + i/10%10;		
		int day = i/100%10*10 + i/1000;
		int k = i*10000+month*100+day;
		if((k<=y&&k>=x)&&(month>=1&&month<=12&&day>=1&&day<=GetMonthDay(i,month)))
		{
			ret++;
		}
	}
	cout<<ret;
	return 0;
}

方法三:

#include <iostream>
using namespace std;
static int GetMonthArray[] = {-1,31,29,31,30,31,30,31,31,30,31,30,31};
int main()
{
	int x,y; cin>>x>>y;
	int cnt = 0;
	for(int month = 1;month<=12;month++)
	{
		for(int day = 1;day<=GetMonthArray[month];day++)
		{
			int year = day%10*1000 + day/10%100*100 + month%10*10 + month/10%100;
			int k = year*10000 + month*100 + day;
			if(k>=x&&k<=y) cnt++;
		}
	}
	cout<<cnt;
	return 0;
}

3.[P2327 SCOI2005] 扫雷 - 洛谷

image-20250310152323499

算法原理

根据题目我们可以使用两组数组来进行模拟这个题目上的要求:

image-20250318153444241

如上图红色线以内为题目用来模拟扫雷,这时候我们就能发现,如果什么都不做的话是无从下手的,但一旦我们将第一个格子填入0或者是1的话后面的数据就会呈现出下面这样的关系,让我们可以将全部的情况模拟出来:

image-20250318153628446

int check1(int n)
{
	a[1] = 0;
	for(int i = 2;i<=n+1;i++) 
	{
		a[i] = b[i-1] - a[i-1] - a[i-2];
	}
}

这时需要判断的就是:

  1. 格子不能填入不为1或0的其他数
  2. 最后一个格子的下一个格子不能填数

满足这两个条件就是一种正确的放雷方式

image-20250318153829269

int check1(int n)
{
	a[1] = 0;
	for(int i = 2;i<=n+1;i++) 
	{
		a[i] = b[i-1] - a[i-1] - a[i-2];
		if(a[i]<0||a[i]>1) return 0;//条件1
	}
	if(a[n+1]==0) return 1;//条件2
	else return 0; 
}

代码实现

#include <iostream>
using namespace std;

const int N = 10010;
int a[N],b[N];

int check1(int n)
{
	a[1] = 0;
	for(int i = 2;i<=n+1;i++) 
	{
		a[i] = b[i-1] - a[i-1] - a[i-2];
		if(a[i]<0||a[i]>1) return 0;
	}
	if(a[n+1]==0) return 1;
	else return 0; 
}
int check2(int n)
{
	a[1] = 1;
	for(int i = 2;i<=n+1;i++) 
	{
		a[i] = b[i-1] - a[i-1] - a[i-2];
		if(a[i]<0||a[i]>1) return 0;
	}
	if(a[n+1]==0) return 1;
	else return 0; 
}
int main()
{
	int n; cin>>n;
	for(int i = 1;i<=n;i++)
	{
		cin>>b[i];
	}
	int ret = 0;
	ret += check1(n);
	ret += check2(n);
	cout<<ret;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值