【每日一记】算法学习1——暴力枚举法

一、循环语法

暴力枚举,是在解题时最简单的方法。尽管可能会因为运行时间太长而导致TLE,但是至少有了一种解题思路,能拿部分分数。so,枚举法也是一种很必要学习的方法。

暴力枚举脱不了循环,循环也就只有两种:

for (变量;运行条件;变量变化)
{
	代码块
}

while (运行条件)
{
	代码块
	[一般会有变量变化]
}

在一些数据较小的情况下,枚举法是一个很好的方法。

二、枚举法思想

顾名思义,就是将所有可能的情况全部进行枚举,并选出符合条件的情况,按照题目要求进行处理。
我们举个例子:

题目描述
输入&输出格式
非常典型,只需要简单的将公鸡(鸡翁),母鸡(鸡母),小鸡(鸡雏)的数量进行枚举就可以了。这是最简单、最暴力、最容易想到的方法。来,直接上代码

#include <iostream>
using namespace std;

int main()
{
	ios::sync_with_stdio(0);  //输入输出优化
	
	int n, m;      //n代表鸡的数量,m代表钱数
	cin >> m >> n; //按顺序输入!
	
	bool flag = false;  //表示是否找到了方案
	for (int i = 0; i <= n; i ++)  //公鸡
	{
		for (int j = 0; j <= n; j ++)  //母鸡
		{
			for (double k = 0; k <= n; k ++)  
			//鸡雏(注意int除以3可能会被取整,出现WA)
			{
				if (i * 5 + j * 3 + k / 3 == m && i + j + k == n) 
				 //钱数总量相等且鸡数总量相等
				{
					cout << i << " " << j << " " << k << endl;
					flag = true; //已经找到方案
				}
			}
		}
	}
	
	if (flag == false) cout << "None" << endl; //没有方案
	
	return 0; 
}

但,很明显,最简单的方法往往会出现超时的情况,这时就要想想该怎么优化了。

三、优化

1.循环次数优化

上面的代码将公鸡、母鸡、小鸡都从0枚举到了n,时间复杂度O(n3) 。当n = 10000时,n3 = 1012 > 108,超过了1s,因此超时了。那么,我们能不能把条件优化?
假设我们的m和n都是100,那么公鸡真的能买到100只吗?5钱一只,那么就算全买公鸡也是100÷5=20只,条件便可以优化成为m/5,同理,母鸡可以变成m/3,而鸡雏可能变成m*3
再想一种情况。假设m=100,n=20时,100÷3=33>20,却还不如直接用n好。
于是,我们就可以得到以下较为优化的代码:

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

int main()
{
	ios::sync_with_stdio(0);
	
	int n, m;
	cin >> m >> n;
	
	bool flag = false;
	for (int i = 0; i <= min(m / 5, n); i ++)
	{
		for (int j = 0; j <= min(m / 3, n); j ++)
		{
			for (int k = 0; k <= min(m * 3, n); k += 3)
			{
				if (i * 5 + j * 3 + k / 3 == m && i + j + k == n)
				{
					cout << i << " " << j << " " << k << endl;
					flag = true;
				}
			}
		}
	}
	
	if (flag == false) cout << "None" << endl;
	
	return 0; 
}

测试点
可以看到,5个测试点经过优化全部AC了。

2.时间复杂度再优化

假设m=n=100,那么上面的代码已经将原来循环1003=1000000降为了
20x33x100=660x100=66000次,时间复杂度由O(106)降为了O(104)。可是真的就只能优化这么多吗?我们需要进行再次的分析。n是我们已知的,在前两次循环当中,我们知道了i和j,那么是否就可以不去枚举k了?则k=n - i - j,就可以由三重循环变为两重循环。

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

int main()
{
	ios::sync_with_stdio(0);
	
	int n, m;
	cin >> m >> n;
	
	bool flag = false;
	for (int i = 0; i <= min(m / 5, n); i ++)
	{
		for (int j = 0; j <= min(m / 3, n); j ++)
		{
			//for (int k = 0; k <= min(m * 3, n); k += 3)
			//{
			int k = n - i - j;
			if (i * 5 + j * 3 + k / 3 == m)
			{
				cout << i << " " << j << " " << k << endl;
				flag = true;
			}
			//}
		}
	}
	
	if (flag == false) cout << "None" << endl;
	
	return 0; 
}
  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值