洛谷--暴力枚举法的4道题【1、四位完全平方数 2、验证子串 3、珠心算测验 4、火柴棒等式】

 

目录

一、四位完全平方数

 二、验证子串

 三、珠心算测验​编辑

四、 火柴棒等式


一、四位完全平方数

首先完全平方数的定义:一个数如果是另一个整数的完全平方,那么就称这个数为完全平方数 

法一、枚举后拆分判断法

扫描二维码关注公众号,回复: 17229788 查看本文章

 首先完全平方数四位数的范围确定:

31*31=961,32*32=1024 ,故最小因数从32开始

100*100=10000,但它不符合题意,故最大因数从99开始

这里采用枚举出所有可能的四位数的因数,然后因数相乘再判断这个数的前两位是否相同,后两位是否相同

注:要学会四位数的拆分,代码如下

#include<iostream>
using namespace std;

int main()
{
	int i;
	for (i = 32; i <= 99; ++i)
	{//先枚举出四位数
		int t = i * i;
		int a = t / 1000;//千位
		int b = t / 100 % 10;//百位
		int c = t % 100 / 10;//十位
		int d = t % 10;//个位
		if (a == b && c == d)
		{
			cout << t << endl;
		}
	}

	return 0;
}

法二、先判断再枚举

 对于一个四位数,前两位、后两位相等的情况,比如1122,4422,9988,前两位、后两位一定是11的倍数,但要注意最高位一定不为0,故高位从1开始,由此利用枚举写出代码

#include<iostream>
using namespace std;

int main()
{
	for (int i = 1; i <= 9; ++i)
	{//一个四位数最高位不能为0,故从1开始
		for (int j = 0; j <= 9; ++j)
		{
			//t就是前两位、后两位相等的一个四位数
			int t = i * 1100 + j * 11;
			for (int k = 32; k <= 99; ++k)
			{
				if (t == k * k)
				{
					cout << t << endl;
					break;
				}
			}
		}
	}

	return 0;
}

 二、验证子串

思路:

首先先输入的子串还是主串不确定,那我们就假设s1为主串,s2为子串就好了,然后再正常用BF算法求解,下标从0开始

1、解释下while中两个判断条件,为什么要同时判断主串和子串是否走到头

①、主串走到头的情况:比如主串一直没找到与子串相匹配的位置,主串会走到头,但此时子串还没到头,故不匹配。

②、 子串走到头的情况:在找的过程中子串匹配成功主串,那子串就会走到头,故匹配成功。故只要有一个条件不满足,就跳出while循环判断

2、关于i = i - j + 1,若下标从0开始则i = i - j + 1,若从1开始就是i = i - j + 2

#include<iostream>
#include<string>
using namespace std;

int main()
{
	string s1, s2;
	cin >> s1 >> s2;
	//使s1是主串,s2是子串
	if (s1.size() < s2.size())
	{//若小于则说明s2才是主串
	 //那就使s1和s2交换,让s1做主串
		string tmp = s1;
		s1 = s2;
		s2 = tmp;
	}
	int Lens1 = s1.size();
	int Lens2 = s2.size();
	int i = 0, j = 0;//利用下标指示位置
	while (i < Lens1 && j < Lens2)
	{
		if (s1[i] == s2[j])
		{//对应字符相等,则后移
			++i;
			++j;
		}
		else
		{
			i = i - j + 1;//主串的i返回到原位置的下一位置
			j = 0;//子串的j回到开头
		}
	}
	if (j == Lens2)
	{//子串都走完了,说明它是主串的子串
		cout << s2 << " is substring of " << s1 << endl;
	}
	else
	{
		cout << "No substring" << endl;
	}

	return 0;
}

 三、珠心算测验

思路:

利用桶计算,比如现有数据1,2,3,4,每个数据对应都有一个桶(用来存放球),对于两个不同的数相加得到另一个数的就加一个球,1+2=3,故3的桶加个球,1+3=4,故4的桶加个球,那么这个球转换到代码中就是++运算,无论多少个球,只要有一个球就说明这个数据是其他不同数的加和,至于你放了几次球是无所谓的,很好的解决了一个数重复出现的问题

#include<iostream>
using namespace std;

//a来存数的个数,利用t的下标来存两个数的加和
int a[105];
int t[20005];//是105而不是100是为了防止数溢出
int main()
{
	int n = 0;
	int cnt = 0;//统计次数
	cin >> n;
	for (int i = 0; i < n; ++i)
		cin >> a[i];

	for (int i = 0; i < n; ++i)
	{
		for (int j = i + 1; j < n; ++j)
		{
			t[a[i] + a[j]]++;//a[i]+a[j]就是相加来的数
		}
	}
	
	for (int k = 0; k < n; ++k)
	{
		//若对于数组中的一个数,桶中对应位置有"球",则++cnt
		if (t[a[k]] > 0)
			++cnt;
	}
	cout << cnt << endl;

	return 0;
}

四、 火柴棒等式

 思路:

用暴力穷举法的唯一难点在于枚举的最大范围是什么?为了提高效率,我们找到的这个最大范围越精准是越好的。

除去+和=,火柴棒最多剩20根,因为1所用火柴棒最少,故用20根火柴最多可枚举到1111,1111+1=1112,除去+和=用了21根>20了,所以每个数最大应该到1111,但实际上运行完发现,最多到711就结束了,0+711=711,共用了24根火柴(不过代码中用1111即可)

#include<iostream>
using namespace std;

int a[10] = { 6,2,5,5,4,5,6,3,7,6 };//统计0~9每个数字所需火柴棒数
int c(int x)
{
	if (x == 0)//若x为0,直接返回他所需火柴棒数
		return 6;

	int sum = 0;//统计x所需的火柴棒总数
	while (x > 0)
	{
		sum += a[x % 10];
		x /= 10;
	}

	return sum;
}

int main()
{
	int n = 0, cnt = 0;
	cin >> n;
	n -= 4;//除去+和=还剩下数字能用的火柴棒个数
	for (int i = 0; i <= 1111; ++i)
	{
		for (int j = 0; j <= 1111; ++j)
		{
			if (c(i) + c(j) + c(i + j) == n)
				++cnt;
		}
	}
	cout << cnt << endl;

	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_74044018/article/details/133146137
今日推荐