- 枚举算法:
百元买鸡
枚举算法的Ì例子:问题如下:某3人有100元打算买100只鸡,其中公鸡为5元每只,母鸡为3元每只,小?鸡为3只1块钱,问可以买多少只公鸡,母鸡,小鸡?
int x, y, z;
for (x = 0; x <= 20; x++)
for (y = 0; y <= 33; y++)
for (z = 0; z <= 100; z++)
if ((x + y + z == 100) && (5 * x + y * 3 + z / 3 == 100) && (z % 3 == 0))
Console.WriteLine("公鸡|:{0}只,母?鸡:{1}只,小鸡:{2}只", x, y, z);
上述运算执行的次数为21*34*101=71114
问题的优化思想如下:
问题中,由于三种鸡的和是固定的,因此只要枚举的两种鸡(x,y),第三种鸡就可以根据约定的条件求得(z=100-x-y),就这样就缩小了枚举的范围变成了双重循环。之所以选择Z,是因为Z的数值较大,优化的效果更好,此时的循环的次数就变成了:21*34=714。
int x, y, z;
for (x = 0; x <= 20; x++)
for (y = 0; y <= 33; y++)
{
z=100-x-y;
if ((x + y + z == 100) && (5 * x + y * 3 + z / 3 == 100) && (z % 3 == 0))
Console.WriteLine("公鸡|:{0}只,母?鸡:{1}只,小鸡:{2}只", x, y, z);
}
问题的再进一步的优化:
如果从数学的角度来考虑枚举算法的进一步的优化,程序的效率就会进一步的优化
根据题意:约束条件为:5X+3Y+Z/3=100;X+Y+Z=100;约去一个Z则得到7X+9Y=100;X+Y+Z=100;所以只要枚举出X(最多位14)则Y,Z的值就可以自然而然的得到确定了。
计算1至N中数字X出现的次数,其中N〉=9,X为0-9
方法1:采用枚举的算法,分立出1-N范围内所有的数据的每一位上的数字,查看是否为X,然后计数。
int cnt = 0, i, k, n, x;
n = Convert.ToInt32(Console.ReadLine());
x = Convert.ToInt32(Console.ReadLine());
for (i=1;i<=n;i++)
{
k=i;
for (; k>0;k/=10)
if (k %10==x)
cnt++;
}
Console .WriteLine ("{0}",cnt);
这个方法的缺点就是时间复杂度太高,计算市一个数中X的出现的次数的时间复杂度为O(log10N),计算全部的数中X的时间复杂度为O(nlog10N)
算法的优化思维如下:
利用数学公式直接计算最终的结果,一次求出数字中X在个无人,视为百威的出现的是次数,在相加得到最终的结果。这里X的范围为1-9,因为=0不符合下列规律,需要单独的计算。
首先规律如下:
(1) 从1到10,在他们的个位数中任意的X都出现了1次
(2) 从1至100,在他们的十位数中,任意的X都出现了10次
(3) 从1至1000,在他们的百位数中,任意的X都出现了100次
以此类推,从1至10i,在他们的左数第二位(右数第i位)中,任意的X都出现了10i-1次。
计算右数第i位包含的X的个数算法:
(1) 取第i位左边(高位)的数字,乘以10i-1,得到基础值a。
(2) 取第i位数字,计算修正值:
如果大于X,则结果为a+10i-1;
如果小于X,则结果为a。
如果等于X,则第i为右边(低位)数字,设为b,最后的结果为a+b+1。时间复杂度为
O(log10N)
代码如下:
int cnt = 0, i, k, n, x, c;
n = Convert.ToInt32(Console.ReadLine());
x = Convert.ToInt32(Console.ReadLine());
for (i = 1; (k = n / i) != 0; i*=10)
{
cnt += (k / 10) * i;
c = k % 10;
if (c> k)
cnt += i;
else if (c == x)
cnt += n - k * i + 1;
}
Console.WriteLine("{0}", cnt);