算法复习笔记(回溯法,分支限界法)

[复习笔记] 算法分析与设计 1. 分治算法 1.1 理论梳理 1.1.1 适用情况 1.1.2 基本步骤 1.1.3 复杂性分析 1.2 算法实例 1.2.1 快速排序 1.2.2 归并排序 1. 分治算法 1.1 理论梳理 先看分治这一部分 1.1.1 适用情况 分治法所能解决的问题一般具有以下几个特征: 该问题的规模缩小到一定的程度就可以容易地解决 该问题可以分解为若干个规模... 阅读详情

回溯法

  回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。
  基本思想:
  在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
  一句话:回溯法最重要的是对解空间树有大致的了解,然后深度遍历解空间树,为了节省时间,还需要进行必要的剪枝操作。如下图所示,就是01背包问题n=3(3样物品时)的解空间树。
  01背包问题的解空间树
  
  回溯法解题的时候常遇到两种类型的解空间树:子集树(选择问题)与排列树(排列问题)。当所给的问题是从n个元素的集合S中找出满足某种性质的子集时相应的空间就是子集树。当所给的问题是确定n个元素满足某种性质的排列时,相应的解空间树就是排列树。
  用回溯法搜索子集树的一般算法课描述如下:

void Backtrack(int t)
{
    if(t>n)
        Output(x);
    else
        for(i=0;i<=1;i++)
        {
            x[t]=i;
            //Constarint(t)和Bound(t)表示当前的约束函数和限界函数
            if(Constarint(t)&&Bound(t))
                Backtrack(t+1);
        }
}

  用回溯法搜索排列树的算法框架可描述如下:

void Backtrack(int t)
{
    if(t>n)
        Output(x);
    else
        for(i=t;i<=n;i++)
        {
            swap(x[t],x[i]);  //swap作用是交换两个元素
            //Constarint(t)和Bound(t)表示当前的约束函数和限界函数
            if(Constarint(t)&&Bound(t))
                Backtrack(t+1);
            swap(x[t],x[i]);
        }
}

  在子集树中,t含义是当前函数在解空间树搜索中相应的层数。
  现在我们根据这两个模板分别举两个例子。
  首先是子集树相关的定向子集求和问题。
  描述: 给一个集合,求出和为某一固定数的子集
  设计思想:利用回溯法,树的每一个节点包括1当前和2层数3剩余所有值之和。关键在于剪枝,若加上下一层的数的和小于所要求的和,则进入左子树,否则一定不可能,左子树便不生成。若减掉当前层数的再加上剩余所有数后的值依然小于所要求的和,那么右子树不生成,否则生成右子树,最后当某一层和等于所要求的和时成立并输出(中间用x[]数组来记录是否选中此数,0为未选中,1为选中)。
  根据设计思想和子集树模板,我们可以写出如下算法代码:

//定向子集求和问题,假设给定W={5,10,12,13,15,18},S=30
#define maxsize 7
#include <IOSTREAM>
using namespace std;

int S=30;
int num=0;
int x[maxsize]={0};
int W[maxsize]={0,5,10,12,13,15,18}; //0号元素不用

void Backtrack(int sum,int k,int r)  //sum为当前的和,k为层数(第几个数),r为剩余数的和
{
    if (sum+W[k]==S)
    {
        num++;
        cout<<"("<<num<<"):";
        cout<<"S=";
        for (int i=1;i<=k;i++)
        {
            if(x[i]==1)
            {
                cout<<W[i]<<"+";
            }
            else
                continue;
        }
        cout<<W[k];
        cout<<endl;
    }
    else if(sum+W[k]+W[k+1]<=S)  //如果到下一层为止的数小于S,则进入左子树,否则一定不可能,左子树便不生成
    {
        x[k]=1;
        Backtrack(sum+W[k],k+1,r-W[k]);
    }
    if (sum+r-W[k]>=S)  //如果减掉当前层数的再加上剩余所有数后的值依然小于30,那么右子树不生成,否则生成
    {
        x[k]=0;
        Backtrack(sum,k+1,r-W[k]);
    }
}

int main()
{   
    cout<<"定向子集求和问题,给定物品重量W={5,10,12,13,15,18},找出和为S=30的子集。"<<endl;
    Backtrack(0,1,73);
    return 0;
}

  接着我们再看一道关于排列树的例子,全排列。
  问题描述:给定一串数字,给出这串数字的所有排列。(假设这串数字为0,1,2)(为了方便画解空间树,所以数字较少)。
  题目的解空间树如下:
  排列的解空间树
  根据排列树的模板,我们可以写出如下代码:

#define n 4
#include <IOSTREAM>
using namespace std;

float A[n]={0,1,2};

void arrange(int k,int m)
{
    int i;
    int temp;
    if(k==m)
    {
        for (i=0;i<=m;i++)
        {
            cout<<A[i]<<" ";
        }
        cout<<endl;
    }
    else
        for (i=k;i<=m;i++)
        {
            temp=A[k];
            A[k]=A[i];
            A[i]=temp;
            arrange(k+1,m);
            temp=A[k];
            A[k]=A[i];
            A[i]=temp;
        }

}

int main()
{
    arrange(0,2);  
    return 0;
}

  写到这里,我突然发现(写之前没有意识到)其实子集树和排列树的道理是一样的,排列树只是进行了非常隐蔽的剪枝操作。排列树模板中循环中i从t->n,而没有经过0->t,因为这一部分已经被隐蔽的剪枝了,在全排列中这0->t的选择是重复的。也就是说,对于排列树,我们也可以根据所有的选择进行0->n循环,只是要根据要求,在if中进行剪枝(比如写一个限制函数要求不能与前面的选择相同),最后得到的效果是相同的,但所花费的时间可能不同。
  比如下面这道汉密尔顿环问题。
  描述:给一个无向图,找出从其中一个点开始走,走过所有点,并且不走回路的路径
  设计思想:定义一个邻接矩阵,1表示相连,0表示不相连。 限制条件是(1)不能和前面的元素重复(2)要保证必须和上一个点有连接,否则不继续向下生成。当k>maxsize,即到达最后一个点时,还要检查是否与最开始的点有连接,有连接则为汉密尔顿环,输出。
  算法代码:

//hamilton环问题
#define maxsize 5
#include <IOSTREAM>
using namespace std;


int sum;
int y[maxsize];
int A[maxsize][maxsize]={{0,1,0,1,0},{1,0,1,1,1},{0,1,0,1,1},{1,1,1,0,1},{0,1,1,1,0}};//定义5*5的邻接矩阵


bool Check(int k)   //保证不能和前面的元素重复
{
    bool flag=true;
    for(int i=0;i<k;i++)
    {
        if (y[i]==y[k])
        {
            flag=false; 
        }
    }
    return flag;
}


bool Check2(int k) 
{
    if (k==0)
    {
        return true;
    }
    else if (A[y[k]-1][y[k-1]-1]==1)
    {
        return true;
    }
    else
        return false;

}

void Backtrack(int k)
{
    if (k>maxsize-1)
    {
        if (A[y[0]-1][y[k-1]-1]==1) //第一个点和最后一个点是否有通路
        {
            sum++;
            cout<<"("<<sum<<"):";
            for (int i=0;i<maxsize;i++)
            {
                cout<<y[i]<<"->";
            }
            cout<<y[0];
            cout<<endl;
        }

    }
    else
    {
        for (int j=0;j<maxsize;j++)
        {

            y[k]=j+1;
            if (Check(k)&&Check2(k))  //必须和上一个点有连接
            {
                Backtrack(k+1);
            }
    }
}

int main()
{   
    Backtrack(0);
    return 0;
}

  这道题虽然属于排列树问题,但也可以对所有的选择均进行判断(for循环从0-maxSize),然后if中check函数去掉已经被选择过的路。

分支限界法

  回溯法的求解目标是找出解空间中满足约束条件的所有解,相比之下,分支限界法的求解目标则是找出满足约束条件的一个解,或是满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。
  此外,回溯法以深度优先的方式搜索解空间,而分支界限法则以广度优先的方式或以最小耗费优先的方式搜索解空间。
  搜索策略:在当前节点(扩展节点)处,先生成其所有的儿子节点(分支),然后再从当前的活节点(当前节点的子节点)表中选择下一个扩展节点。为了有效地选择下一个扩展节点,加速搜索的进程,在每一个活节点处,计算一个函数值(限界),并根据函数值,从当前活节点表中选择一个最有利的节点作为扩展节点,使搜索朝着解空间上有最优解的分支推进,以便尽快地找出一个最优解。
  从活结点表中选择下一扩展结点的不同方式导致不同的分支限界法。最常见的有以下两种:
  1.队列式(FIFO)分支限界法
  队列式分支限界法将活节点表组织成一个队列,并将队列的先进先出原则选取下一个节点为当前扩展节点。
  2.优先队列式分支限界法
  优先队列式分支限界法将活节点表组织成一个优先队列,并将优先队列中规定的节点优先级选取优先级最高的下一个节点成为当前扩展节点。如果选择这种选择方式,往往将数据排成最大堆或者最小堆来实现。
  根据这两种方法我们举两个例子。
  首先是布线问题。
  问题描述:如下图所示,找一条路把ab两点横平竖直最短连接起来,不能碰绿色的障碍物。
  布线问题
  算法思路:
  这里用的是队列式(FIFO)分支限界法。首先定义矩阵PCB[][],并将其初始化,infinite表示不通,0表示通,还有一个PCB2[][]是后面用来标记找路径的,结构体Pos指标是横纵坐标表示位置。一开始将a点入队,队列不空进入循环,利用HorizontalMove[4]={0,1,0,-1},VerticalMove[4]={1,0,-1,0}上下左右走,是在PCB上标记是0的就比当前位置加1,并入队,直到达到终点,这边注意的是a点因为初始值为0,会被修改,影响后面的找路径,所以改回0。然后找路径利用矩阵中周围比自己小1的是最短路径的特点,并在另一个矩阵中记录路径。最后利用所做的各种标记打印图形。(根据上下左右移动的顺序路径会有改变,但都为最短并满足要求的路径)。

//印刷电路板排线问题
#define maxsize 9
#define infinite 9999
#include <IOSTREAM>
using namespace std;
#include <STDLIB.H>
#include "Queue.h"

int HorizontalMove[4]={0,1,0,-1};
int VerticalMove[4]={1,0,-1,0};

int PCB[maxsize][maxsize]={0};   //用来找到路径的电路板矩阵   
int PCB2[maxsize][maxsize]={0};     //用来标记路径的电路板矩阵

typedef struct           //位置的结构体
{
    int row;            //行        
    int col;            //列
}PosNode;

void Print()
{
    /*省略*/
}

void InitializePCB()  //初始化电路板的函数(按题目要求把障碍这些全部设置好,0可通,infinite表示不能通)
{
    for (int i=0;i<maxsize;i++)      //外面的围墙                   
    {
        for (int j=0;j<maxsize;j++)
        {
            if (i<=0||i>=maxsize-1||j<=0||j>=maxsize-1)
            {
                PCB[i][j]=infinite;
            }
            else
            {
                PCB[i][j]=0;
            }
        }
    }
    PCB[1][3]=infinite;
    PCB[2][3]=infinite;
    PCB[2][4]=infinite;
    PCB[3][5]=infinite;
    PCB[4][4]=infinite;
    PCB[4][5]=infinite;
    PCB[5][1]=infinite;
    PCB[5][5]=infinite;
    PCB[6][1]=infinite;
    PCB[6][2]=infinite;
    PCB[6][3]=infinite;
    PCB[7][1]=infinite;
    PCB[7][2]=infinite;
    PCB[7][3]=infinite;
}

void Arrange(PosNode start,PosNode end)
{
    int i;
    int flag=0;//用来判断是否有解  
    PosNode tempnode;
    PosNode nownode;
    LinkQ Q;      //初始化队列
    InitQ(Q);
    EnQ(Q,start);
    while (!EmptyQ(Q))    
    {
        DeQ(Q,tempnode);
        for (i=0;i<4;i++)    //上下左右都走一下
        {
            nownode.row=tempnode.row+HorizontalMove[i];
            nownode.col=tempnode.col+VerticalMove[i];
            if (PCB[nownode.row][nownode.col]==0)
            {

                PCB[nownode.row][nownode.col]=PCB[tempnode.row][tempnode.col]+1;  //比上一个加一
                if (nownode.row==end.row&&nownode.col==end.col)  //到达终点
                {
                    flag=1;
                    return;
                }
                EnQ(Q,nownode);
            }   
        }
    }
    if (flag==0)
    {
        cout<<"无解"<<endl;
        exit(0);
    }
}

void FindPath(PosNode start,PosNode end)   //找到那条路径,利用矩阵中周围比自己小1的是最短路径的特点 
{
    int temp;
    PosNode tempnode;
    PosNode tempnode2;
    temp=PCB[end.row][end.col];
    tempnode.row=end.row;
    tempnode.col=end.col;
    PCB2[end.row][end.col]=1;
    int flag=0;
    while(flag==0)
    {
        for (int i=0;i<4;i++)
        {
            tempnode2.row=tempnode.row+HorizontalMove[i];
            tempnode2.col=tempnode.col+VerticalMove[i];
            if ((temp-1)==PCB[tempnode2.row][tempnode2.col])
            {
                PCB2[tempnode2.row][tempnode2.col]=1;  //在另一个矩阵中记录路径
                temp--;
                tempnode.row=tempnode2.row;
                tempnode.col=tempnode2.col;
                if (tempnode2.row==start.row&&tempnode2.col==start.col)
                {

                    flag=1;
                    break;
                }
                break;
            }
        }
    }
}

int main()
{   
    PosNode start;
    start.row=3;
    start.col=2;
    PosNode end;
    end.row=4;
    end.col=6;
    InitializePCB();
    Print(start,end);
    Arrange(start,end);
    //##Arrgnge是碰到0就改变,因为起点在矩阵中的数值为0,会导致起点数值变2,影响了后面找路径,所以改为0. 
    PCB[start.row][start.col]=0; 
    FindPath(start,end);
    cout<<endl<<endl;
    Print();
    return 0;
}

  然后是关于优先队列分支限界法的著名旅行商问题:
  该问题是在寻求单一旅行者由起点出发,通过所有给定的需求点之后,最后再回到原点的最小路径成本。
  题目如下图所示:
旅行商问题
  算法思路:
  首先,用小顶堆写一个优先队列,并按要求定义好矩阵。定义结构体Node(也是队列中的元素),里面nommoney表示当前的钱,这也是优先队列的优先级,k表示层数,x[]用来记录路径。然后写一个类似于树广搜的函数,一开始都赋0使Node进入队列,队列不空则进入循环如果不是叶子节点的父节点,那么这一层上有可能的值一个个试,如果满足1.不能和前面有重复2.要有连接3.加上钱这一层钱后要小于最优解,则修改结构体值后入队。然后试完后再出队的值就是队列中当前钱最少的那个节点,依次进行,直到到达叶节点的父节点,找出剩余的那个没走过的节点,加上当前节点到那个节点路的钱和那个节点到起点(这里设为1点)的钱是否小于最优解,小于则记录下来。
  算法代码:

//旅行商问题,从1号点开始走
#define maxsize 5
#define infinite 9999
#include <IOSTREAM>
using namespace std;
#include "PriorQueue.h"

//在头文件中已经定义过了,不再重复定义
/*typedef struct
{
    int nowmoney;   //并作为优先级
    int k;   //层数
    int x[maxsize];  //记录路径
}Node;
*/

int bestmoney=999;
int best[maxsize];
int x[maxsize]={0};
int A[maxsize][maxsize]={{infinite,20,30,10,11},{20,infinite,16,4,2},
\{30,16,infinite,6,7},{10,4,6,infinite,12},{11,2,7,12,infinite}};//定义5*5的邻接矩阵

bool Check(int content,Node temp)   //保证不能和前面的元素重复
{
    bool flag=true;
    for(int i=0;i<temp.k;i++)
    {
        if (temp.x[i]==content)
        {
            flag=false; 
        }
    }
    return flag;
}


bool Check2(int content,Node temp) 
{
    if (A[content-1][temp.x[temp.k]-1]!=infinite)
    {
        return true;
    }
    else
        return false;   
}

void TSP()
{
    int i,int j;
    Node tempnode,tempnode2,node;
    node.nowmoney=0;
    node.k=0;
    node.x[0]=1;
    PriorQueue Q;      //初始化优先队列
    InitQueue(Q);    
    EnterQueue(Q,node);
    while (!QueueEmpty(Q))    
    {
        OutQueue(Q,tempnode);
        if (tempnode.k==maxsize-2)   //到达叶节点的父节点
        {
            int flag;
            for (i=1;i<=maxsize;i++)
            {
                for (j=0;j<maxsize;j++)
                {
                    if(tempnode.x[j]==i)
                    {
                        break;
                    }
                }
                if (j==maxsize)
                {
                    break;
                }
            }
            flag=i;
            if (tempnode.nowmoney+A[tempnode.x[tempnode.k]][flag]+A[flag][0]<bestmoney)
            {
                bestmoney=tempnode.nowmoney+A[tempnode.x[tempnode.k]-1][flag-1]+A[flag-1][0];
                for (i=0;i<=tempnode.k;i++)
                {
                    best[i]=tempnode.x[i];
                }
                best[i]=flag;
            }
        }
        else
        {
            for (i=1;i<=maxsize;i++)
            {   
            //1.不能和前面有重复2.要有连接3.加上钱这一层钱后要小于最优解  
                if (Check(i,tempnode)&&Check2(i,tempnode)&&(tempnode.nowmoney+A[tempnode.x[tempnode.k]][i])<bestmoney)  
                {
                    tempnode2.k=tempnode.k+1;       
                    tempnode2.nowmoney=tempnode.nowmoney+A[tempnode.x[tempnode.k]-1][i-1];
                    for (j=0;j<=tempnode.k;j++)
                    {
                        tempnode2.x[j]=tempnode.x[j];
                    }
                    tempnode2.x[tempnode2.k]=i;
                    EnterQueue(Q,tempnode2);
                }
            }
        }
    }   
}

int main()
{   
    TSP();
    cout<<"最优解为:"<<endl;
    for (int i=0;i<maxsize;i++)
    {
        cout<<best[i]<<"->";
    }
    cout<<"1";
    cout<<"\n花费为"<<bestmoney<<endl;
    return 0;
}

  总的来说,回溯法相当于深搜,而分支限界法相当于广搜,为了减小时间复杂度。回溯法通过剪枝,而分支限界法可以通过优先队列的择优选择来减少选择次数,但是确定哪一项数据的为优先级决定了分支限界法的成功与否。

算法设计与分析复习笔记(下) 简介:本文是博主在复习算法设计与分析的笔记,参考了北大算法设计与分析以及王晓东编著的《计算机算法设计与分析》第四版相关内容,如有错误,欢迎指正。 文章目录贪心法分支限界法回溯法 贪心法 贪心选择性质:仅在当前状态下做出最好的选择,进而产生相应的子问题 最优子结构性质:一个问题的最优解包含子问题的最优解 算法设计例子: 例1:活动安排问题 template <class Type> void GreedySelector(int n,Type s[],Type f[],bool A[]) {//s 阅读详情

相关推荐

算法设计与分析期末复习题

一. 选择题 1.Hanoi塔问题如下图所示。现要求将塔座A上的的所有圆盘移到塔座B上,并仍按同样顺序叠置。移动圆盘时遵守Hanoi塔问题的移动规则。由此设计出解Hanoi塔问题的递归算法正确的为:(B) 4. 算法分析中,记号O表示(B ), 记号 表示(A ), 记号 表示(D)。 A.渐进下界 B.渐进上界 C.非紧上界 D.紧渐进界 E.非紧下界 以下关于渐进记号的性质是正确的有:( A) A. B. C. O(f(n))+O(g(n)) = O(min{f(n),g(n)}) D. 4 程

qq_43717119的博客 1万+

【算法学习笔记】4:贪心法,回溯法,分支限界法,解空间树剪枝

[4]贪心算法贪心算法不从整体最优上考虑,而是在局部最优上做出选择。对于很多问题贪心法不能得到整体最优解,但对于某些特殊的问题,仍然可以得到整体最优解。使用贪心算法应满足这些性质: ①最优子结构性质:一个问题的最优解包含的子问题也是最优的。 ②贪心选择性质:整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。 活动安排问题n个活动的集合E,都需要使用同一资源,活动i有开始时间si和

大桔骑士的学习笔记 9640

算法设计与分析复习笔记第六章分支限界法

分支限界法的基本思想分支限界法类似于回溯法,也是一种在问题的解空间树T中搜索问题解的算法。但在一般情况下,分枝限界法与回溯法的求解目标不同。回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分枝限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。所谓“分枝”就是采用广度优先的策略,依次搜索活结点的所有分枝,也就是所有相邻结点。求最优解时,选择哪一个子结点?

weixin_61060664的博客 4693

算法小课堂(九)分支限界法

分支限界法是一种求解最优化问题的算法,常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。其基本思想是把问题的可行解展开,再由各个分支寻找最佳解。在分支限界法中,分支是使用广度优先策略,依次生成扩展结点的所有分支。限界是在结点扩展过程中,计算结点的上界,搜索的同时剪掉某些分支。

qq_62377885的博客 1万+

大学算法分析与设计复习总结

大学算法分析与设计复习总结

ytffhew的博客 7290

当KCF遇见卡尔曼滤波:视觉跟随算法的动态优化实战

本文探讨了KCF算法与卡尔曼滤波在视觉跟随算法中的动态优化实践,通过深度融合策略提升目标跟踪的鲁棒性和实时性。特别针对机器人应用场景,详细解析了在Jetson等嵌入式平台上的优化技巧,包括计算图优化、内存访问优化和多线程流水线设计,实现了30FPS@1080p的稳定跟踪性能。

sugar的博客 956

《算法分析》——布线问题

布线问题(分支限界法)的算法思想 分支限界法和回朔法有相似之处,但是回朔法是搜索问题的所有解,采用深度优先搜索;而分支限界法是搜索问题的最优解,采用的是广度优先搜索; ...

linana123456789的博客 5596

RocketMQ 5.3.1 集成 Spring Boot 3.4.3 就这么简单

RocketMQ 是一个分布式消息中间件,支持发布/订阅模型,具有高吞吐量、高可用性和事务消息等特性。它广泛应用于日志处理、订单系统和异步任务等场景。Spring Boot 3.4.3 集成 RocketMQ 5.3.1 的过程异常简单,仅需少量配置即可实现消息的生产和消费。本文从环境搭建到代码实现,覆盖了核心步骤。

lssffy的博客 1385

分支与限界-旅行售货员问题

算法描述 类似于回溯法,也是一种在问题的解空间树T上搜索问题解的算法。但在一般情况下,分支限界法与回溯法的求解目标不同。回溯法的求解目标是找出T中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。 分支搜索算法 所谓“分支”就是采用广度优先的策略,依次搜索E-结点的所有分支,也就是所有相...

小肥柴YD的博客 7214

雷达参数的设置

采样率又可以叫做采样速率或者,顾名思义就是每秒采集的次数。该值越高,单位时间内对信号的采集越多,采样率的单位可以用Hz或者sps表示(sps是采样率,是每秒采样点的数量,sp表示采样点数),一般1sps=1Hz。采样时间是采样点数和采样周期的乘积得到的结果。假设实际采样率为4560ksps,采样点数为256,那么采样周期为1/4560(ms),那么ADC的采样时间就为256*(1/4560)(ms)=0.056ms=56微秒。

qq_50974341的博客 1912

WPF进阶 | 深入 WPF 依赖项属性:理解其强大功能与应用场景

WPF进阶 | 深入 WPF 依赖项属性:理解其强大功能与应用场景,在 Windows Presentation Foundation(WPF)开发中,依赖项属性是一个核心且强大的特性,它为构建灵活、可扩展的用户界面提供了关键支持。理解并熟练运用依赖项属性,对于开发高效、健壮的 WPF 应用程序至关重要。本文将深入探讨 WPF 依赖项属性,通过丰富的代码示例和对关键概念的详细解释,帮助读者全面掌握这一重要特性及其应用场景。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 4万+

五大常用算法——分治法,动态规划,回溯法,分支界限法,贪心算法

分治法——>分成若干个子问题,例如“排序”。 动态规划——>分成若干个子问题,找出最优解。 贪心算法——>分成若干个子问题,局部最优解,不是最优解,不能用来求最大值或最小值的问题。 回溯法——>深度优先 遍历结点搜索解空间树。找出所有解。 分支限界法——>广度优先或最小耗费优先搜索解空间树。找出最优解。

weixin_45617356的博客 5461

OpenCloudOS9操作系统搭建Confluence8.2.1+Jira企业级WIKI

Atlassian Confluence是一个专业的企业知识管理与协同软件,可用于构建企业wiki

背锅神童的博客 1021

西工大算法分析与设计考试复习笔记2-回溯法,分支限界法

回溯法解决全部解问题需要我们遍历整个解空间树,但对于最优解问题,我们只需寻找其中一条符合要求的最值路径,这种情况下,我们无需对每个子树遍历生成到最底下的叶子结点,不妨先行判断最优解的路径是否包含在目前子树中,否则剪枝。,xn-1},其中分量xi对应第i步的选择。x中各个分量xi所有的取值的组合构成问题的解向量空间,简称为解空间或者解空间树。顺便提醒看到的npuer,应对瓜的考试,把PPT弄懂是最上策,我的复习笔记仅是个人的心得总结提炼,可作为参考启发,但是自己不做题,肯定无法纯熟掌握经典的算法与代码。

2401_87776550的博客 240

VMware如何安装img镜像,VMware如何安装openwrt软路由(含相关工具镜像)

VMware如何安装img镜像,VMware如何安装openwrt软路由(含相关工具镜像)

XiaoqiangClub的博客 4003

天气预测模型:基于时间序列分析的数学建模与实战案例

目录引言时间序列分析介绍使用Matlab进行天气预测实战案例:天气预测结论天气预测一直是气象学和相关领域的重要研究问题之一。数学建模是进行天气预测的有效方法之一,其中时间序列分析是常用的技术。在本篇博客中,我们将介绍时间序列分析的基本原理,演示如何使用Matlab进行模型建立和预测,并通过一个实战案例来展示模型的应用和分析。时间序列分析是一种用于分析和预测时间序列数据的统计方法。天气数据通常具有时间依赖性和随机性,因此时间序列分析可以帮助我们了解天气的变化趋势和规律,并提供对未来天气的预测。时间序列分析通常

YOLO 1545

《软件设计师》复习笔记(10.2)——贪心法、回溯法、数据挖掘、智能优化

假设公路起点A的坐标为0,消防栓的覆盖范围(半径)为20米,10栋房子的坐标为(10,20,30,35,60,80,160,210,260,300),单位为米。以下关于该求解算法的叙述中,正确的是()。考虑一个背包问题,共有n = 5个物品,背包容量为W = 10,物品的重量和价值分别为:w = {2, 2, 6, 5, 4},v = {6, 3, 5, 4, 6},求背包问题的最大装包价值。已知消防栓覆盖范围半径为20米,房子坐标为(10,20,30,35,60,80,160,210,260,300)。

一些知识和经验 1055

高级数据结构之R树(R-tree)

R树(R-tree)是一种将B树扩展到多维情况下得到的数据结构,它最初由Antonin Guttman于1984年提出。B树的结点中会存储一个键的集合,这些键把线分成片段,沿着那条线的点仅属于一个片段。因此,B树使得我们可以很容易地找到点。如果把沿线各处的点表示成B树结点,我们就能够确定点所属唯一子结点,在那里可以找到该点。 Antonin Guttman在他提出R树的经典论文中给出的R树例子...

白马负金羁 1万+

【算法设计与分析】期末复习

【算法设计与分析】期末复习

manerzi的博客 1万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

回溯法采用的搜索策略_算法复习第七篇——分支限界法

2020年5月7日。距离算法考试仅剩两天。这次期末考试,软件学院的要求是指考相关概念,所以本篇文章只针对概念进行讲解。一、知识归纳1.算法思想(1) 类似于回溯法,在问题的解空间树上搜索问题的解(2) 搜索策略①广度优先(BFS)队列式(FIFO)分支限界法栈式(LIFO)分支限界法②最小代价(LC, 最大效益)优先LC分支限界法(3) 按照BFS的原则,一个活结点R成为E-结点 (扩展结点)后,...

weixin_42519733的博客 1105

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【期末考试】《算法分析与设计》期末复习题

田忌赛马:如果3匹马变成n匹,齐王仍然让他的马按从优到劣的顺序出赛,田忌可以按任意顺序选择他的赛马出赛。答:设输入是一个按非降次序排列的元素表A[i:j] 和x,选取A[(i+j)/2]与x比较,如果A[(i+j)/2]=x,则返回(i+j)/2,如果A[(i+j)/2]

海海不掉头发的的博客 1万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

算法分析复习

算法分析考试范围 奔腾答案大多有错,理性看待 考试题型与对应分值: 选择题10道(20分) 简答题4道(20分) 证明题2道(15分) 计算题3道(30分) 算法题1道(15分) 第二章:算法设计与分析 出证明题与选择题,证明题类似于: 证明两个函数之间存在O或Θ的关系。 第三章:递归 不单独出题 第四章:分治法 出小题,大概率出算法题,不出计算题。 第五章:贪心方法 以下可能出证明: ”证明贪心解为最优解“的证明 (PPT5章19页) 定理5.2的证明(ppt5章71页) 定理5.3的证

KQ的博客 7547

fifo算法_算法复习第七篇——分支限界法

2020年5月7日。距离算法考试仅剩两天。这次期末考试,软件学院的要求是指考相关概念,所以本篇文章只针对概念进行讲解。一、知识归纳1.算法思想(1) 类似于回溯法,在问题的解空间树上搜索问题的解(2) 搜索策略①广度优先(BFS)队列式(FIFO)分支限界法栈式(LIFO)分支限界法②最小代价(LC, 最大效益)优先LC分支限界法(3) 按照BFS的原则,一个活结点R成为E-结点 (扩展结点)后,...

weixin_39619270的博客 1278

《算法设计与分析》期末复习精简版

期末考试形式全为大题,重点在于概念的掌握和方法的描述,所以再根据考点进行比较概念层面的复习分治法> 分治法的设计思想: 将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。> 分治法能解决问题的特征: 该问题的规模缩小到一定的程度就可以容易地解决; 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优 子结构性质 利用该问题分解出的子

晨阳再升的博客 3万+

回溯法采用的搜索策略_算法设计与分析复习题最终版 -

一、填空题:1、 算法就是一组有穷的_____________,它们规定了解决某一特定类型问题的一系列运算。2、 f(n)= 6×2+n,f(n)的渐进上界是_____________。 3、 递归与分治算法应满足条件:____________与_____________。 4、 算法的复杂性是______的度量,是评价算法优劣的重要依据。5、 以广度优先搜索或以最小耗费方式搜索问题解的算法称为_...

weixin_39736547的博客 1032
上一篇: 算法复习笔记(分治法、动态规划、贪心算法)
下一篇: 01背包类型问题的两种解法
King来写代码
博客等级 码龄12年 68粉丝 30原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值