贪心+dfs

贪心算法:区间选点 贪心:短视的一个行为,每次选点只看当前点的占据数量最大 ———局部最优解

AcWing 905区间选点

1将每个区间按右端点从小到大排序

2从前往后依次枚举每个区间 (查看右端点,右端点占据的区间数量比较多) 如果当前区间已经被包含点,则直接pass,否则选择当前区间的右端点。

证明ans

证明ans>=cnt : cnt可行方案是一个区间集合,区间从小到大排序,两两之间不相交。

所以覆盖每一个区间至少需要cnt个点。 (证明得出的解就是答案的论证过程)AcWing 905. 区间选点 - AcWing

2 AcWing 908最大不相交区间数量

证明ans

证明ans>=cnt 因为重点是我们排序的时候是把每个端点的右边作为排序条件的。所以就第一个选择的左端点就不会存在说第一个端点中包含了第二个端点,因为第一个是把每个端点的右边作为排序条件的

3AcWing 906 区间分组

1将每个区间的左端点从小到大排序(可以理解为是为了让每个组的区间都更加紧密,避免浪费空间。如果按照右端点进行排序的话,由于不知道左端点的位置,可能会造成同一组之间差距过大,导致空间的浪费,最后导致组的数目大于正确答案。

2 从前往后处理每个区间 判断能否将其放到某个现有的组中(看某一组的最后一个右端点是否大于新区间的左端点,如果大于,则不能放置,如果小于,则新区间就可以放置到该组中,同时这个组的最后一个右端点进行更新。

3AcWing 907区间覆盖

1将所有区间按左端点从小到达排序

2从前往后依次枚举每个区间,在所有的能覆盖start的区间中,选择右端点最大的区间,然后将start更新成右端点的最大值

接下来可以简单证明ans == cnt 可以通过前面设置的条件找到的cnt,然后把cnt一步步的转换成ans,得出ant>=cnt

Huffman树

AcWing_148_合并果子 只需要用一个优先队列就能写出来了

AcWing_913_排队打水

n个人打水,打水的时间各不相同,如何安排他们的打水顺序,才能够使所有人的的等待时间最少?

AcWing_104_货仓选址

即一个数组,然后在数轴中选择一个点,然后来回走,直到经过了所有的点,问走的最短路程是多少,用的是右上角的哪一个不等式来解决的,之后就把数轴上的点两两相结合 ,然后a1和an结合,一直到最小的中间,如果是奇数个,最后刚好·1剩下一个点,n/2,如果是偶数的话,中间两个点,任选一个就好。

AcWing_125_耍杂技的牛

n头牛玩叠罗汉根据Scanner会给他们各自的重量以及承受力,然后每头牛的风险就是它的头顶的重量减去它的风险,如何排序n头牛来让风险最小的?所以最下面的牛就应该是重量最大且承受力最强大的? 应该尝试模拟,来推断一个数学公式,严谨的得出答案,先动笔,思路就会慢慢出现。

y总所推断

如果是这样写的排序,然后写了自定义排序方法的话,在return中记得写括号。来让编译器分的清除,,

Arrays.sort(arr, new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return (o1[0]+o1[1]) - (o2[0]+o2[1]);
    }
});

AcWing_dfs1_842_排列数字

回溯+递归,注意当回溯的时候要恢复现场

AcWing_dfs2_843_n皇后问题

dfs函数,每次调用都是往里面深入的走了一层,然后当在循环中调用dfs函数的之后也就是这一层的回溯已经完成,所以需要把它的现场也回溯,就是把几个数组的值恢复原貌

for (int j = 0; j < n; j++) {
    if(!col[j] && !dg[j + i] && !udg[n - i + j]){
        g[i][j] = 'Q';
        col[j] = dg[j + i] = udg[n - i + j] = true;
        dfs(i+1);
        col[j] = dg[j + i] = udg[n - i + j] = false;
        g[i][j] = '.';
    }
}

这是另外一种方法,其中if(x == n) 的判断中的return是很重要的,因为调用dfs递归的地方并不是在for循环中,所以有可能无限递归,所以一定要写判断终止当前递归的代码。/

private static void dfs(int x, int y, int s) { //从左到右,从上到下,依次遍历,找到可以放皇后的地方, //y是从左到右,遍历一行就加一行从新来 if (y == n) { y = 0; x++; } if (x == n) { if (s == n) { //如果成功的找到了n个皇后就把答案输出。 

    private static void dfs(int x, int y, int s) {
        //从左到右,从上到下,依次遍历,找到可以放皇后的地方,
        //y是从左到右,遍历一行就加一行从新来
        if (y == n) {
            y = 0;
            x++;
        }
        if (x == n) {
            if (s == n) {
                //如果成功的找到了n个皇后就把答案输出。
                for (int j = 0; j < n; j++) {
                    for (int k = 0; k < n; k++) {
                        System.out.printf("%c", g[j][k]);
                    }
                    System.out.println();
                }
                System.out.println();
            }
            return;
        }
        //不放皇后
        dfs(x, y + 1, s);
        // 放置皇后
        if (!row[x] && !col[y] && !dg[y + x] && !udg[n - y + x]) {
            g[x][y] = 'Q';
            row[x] = col[y] = dg[x + y] = udg[n - y + x] = true;
            dfs(x, y + 1, s + 1);
            row[x] = col[y] = dg[x + y] = udg[n - y + x] = false;
            g[x][y] = '.';
        }
    }

DFS深度优先搜索)是一种常见的图遍历算法,它使用递归或栈的方式,从一个顶点出发,沿着一条路径一直到达最深的节点,然后回溯到上一层继续遍历其他节点。DFS常被用于解决图的连通性问题、路径问题等。在实际应用中,可以使用DFS进行状态搜索、图的遍历、拓扑排序等。 剪枝是指在搜索过程中,通过一系列的策略判断,提前终止当前搜索分支,并跳过一些无用的搜索路径,从而减少搜索时间。剪枝的核心在于提前排除某些明显不符合条件的状态,以减少无效搜索的时间开销,提高效率。在算法设计中,剪枝通常会利用一些特定的性质或条件进行判断,从而缩小搜索空间。 动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划通常用于求解最优化问题,它通过定义状态状态转移方程,采用自底向上的思路,逐步求解每个子问题的最优值,最终得到原问题的最优解。动态规划的核心是存储已经计算过的子问题的解,避免了重复计算。 贪心算法是一种基于局部最优解的策略,它通过每一步选择在当前状态下最优的解,以期望得到全局最优解。贪心算法的基本思想是由局部最优解推导出全局最优解,通常通过贪心选择性质、最优子结构贪心选择构成三部分。贪心算法相比其他算法,如动态规划,它的优势在于简单、高效,但缺点在于不能保证获取到全局最优解,只能得到一个近似解。 综上所述,DFS、剪枝、动态规划贪心算法算法设计问题求解中都发挥着重要的作用。具体使用哪种算法取决于问题的性质要求,需要在实际应用中进行综合考虑选择。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值