模拟递归回溯贪心专题入门

一、模拟------用最基本的方式思考问题。

简单模拟(模拟某个过程): 在试题中,已经详细给出了完成某一过程的步骤或规则,程序只须严格按照题意要求,模拟过程即可。

1、直叙式模拟(按照题意要求,直接模拟过程)

要忠实于原题,认真审题,千万不要疏漏任何条件,精心设计方便模拟的数据结构。

2、筛选法模拟(模拟过程中产生的所有可能的解,组成一个筛)

先从题意中找出约束条件,然后将筛中的每一个可能的解解放到约束条件的过滤器上,一次一次地将不符合条件的解过滤掉,最后在筛中的即为问题的解。

3、构造法模拟

需要完整精确地构造出反映问题本质的数学模型,并根据该模型设计表示状态变化的参数,计算模拟结果。

二、递归------程序调用自身的编程技巧称为递归。

是子程序在其定义或说明中直接或间接调用自身的一种方法。

在递归过程中,系统每一层的返回点局部变量等用栈来存储。

  递归时,当前层的返回点和局部变量入栈;

  回溯时,当前层的返回点和局部变量出栈;

如果递归过程无法到达递归边界或递归次数过多,则会造成栈溢出。

三、回溯------搜索算法中的一种控制策略。

搜索从初始状态出发,运用题目给出的条件,规则,按照纵深搜索的顺序递归扩展所有可能的情况,从中找出满足题意要求的解答。当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。

回溯法解题的考虑因素:

  1、定义状态:如何描述问题求解过程中每一步的状况。

  2、边界条件:在什么情况下,程序不再递归下去。

  3、搜索范围:若当前子状态不满足边界条件,则扩展子状态。

  4、约束条件和最优性要求:扩展出的子状态应满足什么条件方可继续递归。

一般流程:

void run(当前状态)
{
    if(当前状态为最佳目标状态)
    {
        记下最优结果;
        return; 
    }
    for(int i=算符最小值;i<=算符最大值;++i)
    {
        算符i作用于当前状态,扩展出一个子状态;
        if(子状态满足约束条件&&子状态满足最优化性要求)
        return(子状态); 
     } 
 } 

例:POJ1979 http://poj.org/problem?id=1979 

递归过程为search(i,j),其中

  1、状态:男子当前的位置(i,j),(i,j)为子程序的值参。递归调用search(row,col)后,便可得到男子经过的瓷砖数ans;

  2、约束条件:若当前瓷砖在地图外,或不可访问,或已访问则回溯,否则设访问标记为true,经过的瓷砖数+1;

  3、搜索范围为:(i,j)的相邻四个点,依次递归调用。

//第一次写,自己瞎写的丑陋AC代码= =
#include <cstdio> #include <iostream> #include <cstring> using namespace std; int ans=1,m,n; char map[22][22]; bool visited[22][22]; int dfs(int x,int y) { int i; map[x][y]='#'; visited[x][y]=false; ans++; if(x-1>=0&&visited[x-1][y]&&map[x-1][y]!='#') { dfs(x-1,y); } if(x+1<m&&visited[x+1][y]&&map[x+1][y]!='#') { dfs(x+1,y); } if(y-1>=0&&visited[x][y-1]&&map[x][y-1]!='#') { dfs(x,y-1); } if(y+1<n&&visited[x][y+1]&&map[x][y+1]!='#') { dfs(x,y+1); } return ans; } int main() { int i,j; //freopen("Atext.in","r",stdin); while(cin >> n >> m,m&&n)  //这地方先输入的是列数n,后输入的是行数m,= = ,害我卡半天 { ans=0; memset(visited,true,sizeof(visited)); for(i=0;i<m;i++) for(j=0;j<n;j++) cin >> map[i][j] ; for(i=0;i<m;i++) { for(j=0;j<n;j++) { if(map[i][j]=='@') { dfs(i,j); cout << ans << endl; break; } } if(ans) break; } } return 0; }

 四、贪心------Greedy Algorithm

贪心:在问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体上加以考虑,它所作出的仅仅是在某种意义上的局部最优解(是否是全局最优,需要证明)。

  若要用贪心算法求解某问题的整体最优解,必须首先证明贪心的思想在该问题的应用结果就是最优解!

例一、事件序列问题(区间调度问题)hdu2037

例二、区间覆盖问题

例三、hdu1050

求解问题的基本步骤:

1、从问题的某个初始解出发。

2、采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个部分解,缩小问题的范围或规模。

3、将所有部分解综合起来,得到问题的最终解。

例:hdu1052田忌赛马(上海2004 区域赛)很多贪心的题像此题一样不是最朴素的贪心,而是需要作出一些变化。

这些都是ACM入门的基本算法(= =),个人总结,简单介绍。

原文地址:https://www.cnblogs.com/Cloud-king/p/8317615.html