zoukankan      html  css  js  c++  java
  • 模拟递归回溯贪心专题入门

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

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

    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入门的基本算法(= =),个人总结,简单介绍。

  • 相关阅读:
    微信开放平台:OpenAPI、云开发与基础管理能力升级
    腾讯刘颖:从容器到低代码,腾讯云原生技术演进历程
    十年老站长心声:我为什么选择把 Hexo 网站迁移到 Webify
    腾讯云发布微搭生态开放计划,与合作伙伴携手共创产业未来
    SQL Server附加数据库出现错误5123的正确解决方法
    数据分页获取(二)
    Select语句
    数据分页获取(一)
    SQL Server中行转列原理
    QT实现Linux下系统监控小工具之二
  • 原文地址:https://www.cnblogs.com/Cloud-king/p/8317615.html
Copyright © 2011-2022 走看看