算法学习 -- 枚举

在学习枚举算法之前,首先问有关枚举的几个问题

1. 为什么要进行枚举?

2. 需要对哪些对象进行枚举?

3. 如何进行枚举?

4. 枚举的结束条件是什么?

现在针对两个使用枚举算法的实例对以上问题进行分析.

实例一:熄灯问题

给定一个5×6的棋盘,上面有灯,每个灯都有各自的按钮,每个按钮按下去都会使其自己和周围的上下左右四盏灯改变(原来熄灭的变亮,原来亮的变灭),如何操作按钮使这个棋盘上所有灯都熄灭。

实例二:青蛙问题

一个5000×5000的稻田,有很多青蛙从这个稻田上跳过,每只青蛙跳过的步长不一样,青蛙每次总是沿着一条直线跳跃稻田(至少3个稻子),农民早上起来看到被踩踏的稻子,希望找到造成最大损害的那只青蛙经过的路径。

第一个问题:为神马要枚举?

因为解决这个问题可能不止一个方案,然而目前我并不知道哪个方案可以,仅仅知道如果按照这个方案操作造成的结果,这个结果是否符合最后的要求并不清楚。需要进一步实验验证。

实例一,总共有5×6个按钮可以操作,但并不知道按下哪些按钮会导致所有灯都熄灭。实例二,总共有5000×5000个稻子,被踩踏的稻子也很多,但是并不知道哪些稻子是被某只青蛙踩踏的,而且是最多的。

第二个问题:需要对哪些对象进行枚举?

接着上个问题所述,假定一个假设,接着进行这个假设,通过这个假设来进行推理,推理出一个结果,这个结果会接着推理下一个结果,顺序下去,最后可以推导出最终的结果,最终的结果是不是题目要求的结果。而这而的假设就是我们需要枚举的对象。这个假设要求可以推得最后的唯一结果,同时它必须不是很多,否则复杂度很大。

实例一,因为下一行的按钮负责将上一行的灯熄灭,一行一行的熄灭,只要第一行的按钮被按下去了,第一行的灯状态就可以确定,第二行的按钮只需要将第一行的熄灭就行,那么第二行的按钮状态也是确定的,依次类推,到最后第五行时,第五行的按钮负责熄灭了第四行的灯,但是不一定使第五行的灯熄灭。所以需要枚举的对象是第一行的按钮状态。

实例二,因为被踩踏的稻子数至少为3个,所以可以将这些被踩踏的任意两个稻子作为一只青蛙经过的路径。任意两个稻子就决定了这只青蛙的步长,根据步长就可以判断下这只青蛙的下一步的位置,依次可以推断出最后一个稻子的位置,就可以知道这只青蛙是不是踩踏最多的那只了。

第三个问题:如何进行枚举?

通过对第二个问题的分析,我们知道了需要对哪些对象进行枚举,接下来需要知道如何对这些对象进行枚举。具体如何枚举需要看所要枚举的对象。

实例一,需要枚举的对象是第一行的按钮状态,因为按下用1表示,不按用0表示,在枚举的过程中,实际是对第一行的6个按钮进行枚举,因为这六个按钮都是0和1,可以看作二进制数,枚举就是二进制不断加一的过程。

实例二,需要枚举的对象是踩踏稻子中任意两个稻子,实际是对n个数中任意两个数进行遍历,外层循环遍历 i 从1到n - 1, 内层循环遍历 j 从 i 到 n。

第四个问题:枚举的结束条件是什么?

通过问题二的分析知道,在某个假设,经过一步一步的推导,看最后的结果是否符合问题给出的条件或约束,如何符合,那枚举就可以结束,说明这个枚举就是最后的答案。

实例一, 第五行的按钮熄灭了第五行的灯,则符合将灯全部熄灭这一要求,所以枚举结束,获得正确的按钮。

实例二,最后一个稻子位置在被毁稻子列表中,而且这个枚举情况下的被毁稻子数最多,则枚举结束,可以判定这条路径就是被毁最多路径。

时间: 2024-10-13 17:10:35

算法学习 -- 枚举的相关文章

算法学习——枚举之最简真分数

算法描述 统计分母在指定区间[100,999]的最简真分数(分子小于分母,且分子分母无公因数)共有多少个,并求这些最简真分数的和 算法思路 对于指定区间,分母的枚举范围为 100~999 即是输入的a与b,分子最小为1,最大则比分母少一(等于分母的话就无意义) 分子与分母与某个数整除,如果同为0,这说明分子与分母有公因数 算法实现 int a,b;//上限与下限 boolean isCommon = false;//分子与分母无公因数 long m=0;//公因数的个数 int t; doubl

算法学习——枚举之基于素数的代数和

算法描述 基于素数的代数和 s(n) = (1/3)-(3/5)-(5/7)+(7/9)+...+(2n-1)/(2n+1) 分子与分母中有且只有一个素数时符号取+ 分子与分母都不是素数或者都是素数,则前面的符号取- 1.求s(2016) 2.设1<=n<=2016,求当n为多大时,s(n)最大 3.设1<=n<=2016 求当n为多大时,s(n)最接近0 算法思路 设置一个二维数组存放数值 a[i][1]存放2i+1 a[i][0]存放0或1 如果2i+1是素数,则存放0,不为素

dinic算法学习(以poj1273为例)

Dinic 算法模板 Dinic算法是一种比较容易实现的,相对比较快的最大流算法. 求最大流的本质,就是不停的寻找增广路径.直到找不到增广路径为止. 对于这个一般性的过程,Dinic算法的优化如下: (1)Dinic算法首先对图进行一次BFS,然后在BFS生成的层次图中进行多次DFS. 层次图的意思就是,只有在BFS树中深度相差1的节点才是连接的. 这就切断了原有的图中的许多不必要的连接.很牛逼! 这是需要证明的,估计证明也很复杂. (2)除此之外,每次DFS完后,会找到路径中容量最小的一条边.

算法学习 - 表达树的建立(后缀表达式法),树的先序遍历,中序遍历,后序遍历

表达树就是根据后缀表达式来建立一个二叉树. 这个二叉树的每个叶子节点就是数,真祖先都是操作符. 通过栈来建立的,所以这里也会有很多栈的操作. 树的先序遍历,中序遍历,后序遍历的概念我就不讲了,不会的自行百度,不然也看不懂我的代码. 下面是代码: // // main.cpp // expressionTree // // Created by Alps on 14-7-29. // Copyright (c) 2014年 chen. All rights reserved. // #includ

我的算法学习之路

关于 严格来说,本文题目应该是我的数据结构和算法学习之路,但这个写法实在太绕口--况且CS中的算法往往暗指数据结构和算法(例如算法导论指的实际上是数据结构和算法导论),所以我认为本文题目是合理的. 这篇文章讲了什么? 我这些年学习数据结构和算法的总结. 一些不错的算法书籍和教程. 算法的重要性. 初学 第一次接触数据结构是在大二下学期的数据结构课程.然而这门课程并没有让我入门--当时自己正忙于倒卖各种MP3和耳机,对于这些课程根本就不屑一顾--反正最后考试划个重点也能过,于是这门整个计算机专业本

算法学习三阶段

?? 第一阶段:练经典经常使用算法,以下的每一个算法给我打上十到二十遍,同一时候自己精简代码, 由于太经常使用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都能够把程序打 出来. 1.最短路(Floyd.Dijstra,BellmanFord) 2.最小生成树(先写个prim,kruscal 要用并查集,不好写) 3.大数(高精度)加减乘除 4.二分查找. (代码可在五行以内) 5.叉乘.判线段相交.然后写个凸包. 6.BFS.DFS,同一时候熟练hash 表(要熟,要灵活,代码要

周总结(2017.2.16):第一周算法学习。

周总结:算法学习总结之DFS和BFS 一:DFS算法 目的:达到被搜索结构的叶节点. 定义:假定给定图G的初态是所有的定点都没有访问过,在G中任选一定点V为初始出发点,首先访问出发点并标记,然后依次从V出发搜索V的每个相邻点W,若W未曾出现过,则对W进行深度优先遍历(DFS),知道所有和V有路径相通的定点被访问. 如果从V0开始寻找一条长度为4的路径的话: 思路步骤: 先寻找V0的所有相邻点:dis{v1,v2,v3},V1没有访问过,所以对V1进行深度遍历并将V1标记为访问过,此时路径长度为1

算法学习 - 01背包问题(动态规划C++)

动态规划 01背包 问题描述 求解思路 代码实现 放入哪些物品 代码 动态规划 我在上一篇博客里已经讲了一点动态规划了,传送门:算法学习 - 动态规划(DP问题)(C++) 这里说一下,遇到动态规划应该如何去想,才能找到解决办法. 最主要的其实是要找状态转移的方程,例如上一篇博客里面,找的就是当前两条生产线的第i个station的最短时间和上一时刻的时间关系. minTime(station[1][i]) = minTime(station[1][i-1] + time[i], station[

LCA 算法学习 (最近公共祖先)poj 1330

poj1330 在求解最近公共祖先为问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,处理技巧就是在回溯到结点u的时候,u的子树已经遍历,这时候才把u结点放入合并集合中,这样u结点和所有u的子树中的结点的最近公共祖先就是u了,u和还未遍历的所有u的兄弟结点及子树中的最近公共祖先就是u的父亲结点.这样我们在对树深度遍历的时候就很自然的将树中的结点分成若干的集合,两个集合中的所属不同集合的任意一对顶点的公共祖先都是相同的,也就是说这两个集合的最近公共祖先只有一个.时间复杂度为O(n+q