算法:分治

算法描述

分治 ( Divide and Conquer ) ,字面上的解释是“分而治之”,就是把一个复杂的问题划分成多个相同或者相似的子问题,直到子问题可以简单的直接求解,然后将子问题的解进行合并从而得出原问题的解。在计算机科学中,分治法就是运用分治思想的一种很重要的算法。分治法是很多高效算法的基础,如排序算法(快速排序,归并排序),傅里叶变换等等。

其大概流程其实就是分为三步:分解 -> 解决 -> 合并。

  1. 分解原问题
  2. 分解到可以求解的边界之后,进行递归求解 ( 分治算法很大程度上是基于递归的 )
  3. 将子问题的解进行合并

分治法能解决的问题特征:

  1. 原问题在分解到一定程度就可以容易的解决
  2. 原问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质,利用该问题分解出的子问题的解可以合并为原问题的解
  3. 子问题相互独立 ( 如果子问题不相互独立,分治法会造成很多重复的计算,这样的情况我们一般会考虑使用动态规划)

经典例题:棋盘覆盖

棋盘覆盖问题要求在2^k * 2^k 个方格组成的棋盘中,给定了一个特殊点,用一种方案用四种 L 型骨牌实现对除该特殊点的棋盘实现全覆盖。

在这里插入图片描述

棋盘如图,黑色为特殊方格要求将L型骨牌放进去 ( 当时老师给的是一个 8*8 的棋盘,看着棋盘整个人都呆住了 )

解决方案就是利用分治法,将棋盘分成四个部分,如果该特殊点在其中的一部分我们就递归他,如果不在,那么我们就假设一个点为特殊点,同样递归下去,直到边长为 1 不可再分。

左上角的子棋盘(若不存在特殊方格):则将该子棋盘右下角的那个方格假设为特殊方格;

右上角的子棋盘(若不存在特殊方格):则将该子棋盘左下角的那个方格假设为特殊方格;

左下角的子棋盘(若不存在特殊方格):则将该子棋盘右上角的那个方格假设为特殊方格;

右下角的子棋盘(若不存在特殊方格):则将该子棋盘左上角的那个方格假设为特殊方格;

这个图可能更加明显的观察出来
在这里插入图片描述

具体代码如下

#include <iostream>
#include <math.h>

using namespace std;

int board[101][101];
int tile = 0;

void chessBoard(int tr, int tc, int dr, int dc, int siz) {
    if (siz == 1) return;
    int t = ++tile;
    int new_s = siz / 2;
    if (dr < tr + new_s && dc < tc + new_s)//左上
        chessBoard(tr, tc, dr, dc, new_s);
    else {
        board[tr + new_s - 1][tc + new_s - 1] = t;
        chessBoard(tr, tc, tr + new_s - 1, tc + new_s - 1, new_s);
    }
    if (dr < tr + new_s && dc >= tc + new_s)//右上
        chessBoard(tr, tc + new_s, dr, dc, new_s);
    else {
        board[tr + new_s - 1][tc + new_s] = t;
        chessBoard(tr, tc + new_s, tr + new_s - 1, tc + new_s, new_s);
    }
    if (dr >= tr + new_s && dc < tc + new_s)//左下
        chessBoard(tr + new_s, tc, dr, dc, new_s);
    else {
        board[tr + new_s][tc + new_s - 1] = t;
        chessBoard(tr + new_s, tc, tr + new_s, tc + new_s - 1, new_s);
    }
    if (dr >= tr + new_s && dc >= tc + new_s)//右下
        chessBoard(tr + new_s, tc + new_s, dr, dc, new_s);
    else {
        board[tr + new_s][tc + new_s] = t;
        chessBoard(tr + new_s, tc + new_s, tr + new_s, tc + new_s, new_s);
    }
}

int main() {
    int k, r, c, l;
    cin >> k >> r >> c;
    l = pow(2, k);
    chessBoard(0, 0, r, c, l);
    for (int i = 0; i < l; i++) {
        for (int j = 0; j < l; j++) {
            printf("%d ", board[i][j]);
        }
        printf("\n");
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值