一、循环语法
暴力枚举,是在解题时最简单的方法。尽管可能会因为运行时间太长而导致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;
}