8.3递归与分治

1.棋盘覆盖问题:

分治算法:

①把棋盘分成四份  ②递归解决,当不能再分时返回  ③不用合并,边递归边打表就行

在一个 2^k * 2^k 个方格组成的棋盘中,若恰有一个方格与其它方格不同,则称该方格为一特殊方格,称该棋盘为一特殊棋盘。显然特殊方格在棋盘上出现的位置有 4^k 种情形。因而对任何 k>=0 ,有 4^k 种不同的特殊棋盘。下图所示的特殊棋盘为 k=2 时 16 个特殊棋盘中的一个。

《8.3递归与分治》

在棋盘覆盖问题中,要用下图中 4 中不同形态的 L 型骨牌覆盖一个给定的特殊棋牌上除特殊方格以外的所有方格,且任何 2 个 L 型骨牌不得重叠覆盖。易知,在任何一个 2^k * 2^k 的棋盘中,用到的 L 型骨牌个数恰为 (4^k-1)/3 。

《8.3递归与分治》

用分治策略,可以设计解棋盘问题的一个简捷的算法。
当 k>0 时,将 2^k * 2^k 棋盘分割为 4 个 2^(k-1) * 2^(k-1) 子棋盘,如下图所示。

《8.3递归与分治》

特殊方格必位于 4 个较小子棋盘之一中,其余 3 个子棋盘中无特殊方格。为了将这 3 个无特殊方格的子棋盘转化为特殊棋盘,我们可以用一个 L 型骨牌覆盖这 3 个较小的棋盘的汇合处,如下图所示,这 3 个子棋盘上被 L 型骨牌覆盖的方格就成为该棋盘上的特殊方格,从而将原问题化为 4 个较小规模的棋盘覆盖问题。递归的使用 这种分割,直至棋盘简化为 1×1 棋盘。

《8.3递归与分治》

#include <iostream>   //湖南师范大学OJ-<span style="font-family: Tahoma; text-align: -webkit-center;">10432 </span>
#include <cstdio>
#include<string.h>
using namespace std;
int biao[70][70],now = 1;
void solve(int x1,int x2,int y1,int y2,int xx,int yy)
{
    if(x1 == x2 && y1 == y2) return;
    int m1 = x1 + (x2 - x1) / 2;  //m1、m2是两个中间点
    int m2 = y1 + (y2 - y1) / 2;  //m1、m2是两个中间点
    int xx1,xx2,xx3,xx4,yy1,yy2,yy3,yy4;
    if(xx >= x1 && xx <= m1 && yy >= y1 && yy <= m2)  //在第一个格里
    {
        biao[m1 + 1][m2] = now;
        biao[m1][m2 + 1] = now;
        biao[m1 + 1][m2 + 1] = now;
        xx1 = xx;
        yy1 = yy;
        xx2 = m1 + 1;
        yy2 = m2;
        xx3 = m1;
        yy3 = m2 + 1;
        xx4 = m1 + 1;
        yy4 = m2 + 1;
    }
    else
    if(xx >= m1 + 1 && xx <= x2 && yy >= y1 && yy <= m2)  //在第二个格子里
    {
        biao[m1][m2] = now;
        biao[m1 + 1][m2 + 1] = now;
        biao[m1][m2 + 1] = now;
        xx1 = m1;
        yy1 = m2;
        xx2 = xx;
        yy2 = yy;
        xx3 = m1;
        yy3 = m2 + 1;
        xx4 = m1 + 1;
        yy4 = m2 + 1;
    }
    else
    if(xx >= x1 && xx <= m1 && yy >= m2 + 1 && yy <= y2)  //在第三个格里
    {
        biao[m1][m2] = now;
        biao[m1 + 1][m2] = now;
        biao[m1 + 1][m2 + 1] = now;
        xx1 = m1;
        yy1 = m2;
        xx2 = m1 + 1;
        yy2 = m2;
        xx3 = xx;
        yy3 = yy;
        xx4 = m1 + 1;
        yy4 = m2 + 1;
    }
    else
    if(xx >= m1 + 1 && xx <= x2 && yy >= m2 + 1 && yy <= y2)  //在第四个格子里
    {
        biao[m1][m2] = now;
        biao[m1 + 1][m2] = now;
        biao[m1][m2 + 1] = now;
        xx1 = m1;
        yy1 = m2;
        xx2 = m1 + 1;
        yy2 = m2;
        xx3 = m1;
        yy3 = m2 + 1;
        xx4 = xx;
        yy4 = yy;
    }
    now++;
    solve(x1,m1,y1,m2,xx1,yy1);  //第一个格子
    solve(x1,m1,m2 + 1,y2,xx3,yy3);  //第三个格子
    solve(m1 + 1,x2,y1,m2,xx2,yy2);  //第二个格子
    solve(m1 + 1,x2,m2 + 1,y2,xx4,yy4);  //第四个格子
}
int main()
{
//    freopen("out.txt","w",stdout);
    int n;
    cin>>n;
    for(int i = 0;i < n;i++)
    {
        int x,y,t;  //t是行数或列数
        now = 1;
        memset(biao,0,sizeof(biao));
        cin>>t>>x>>y;
        x++;y++;
        solve(1,t,1,t,x,y);
        printf("CASE:%d\n",i + 1);
        for(int j = 1;j <= t;j++)
        {
            for(int k = 1;k <= t;k++)
            {
                if(k == 1)
                    printf("%d",biao[j][k]);
                else
                    printf("\t%d",biao[j][k]);
            }
            printf("\n");
        }
    }
	return 0;
}

2.循环日程表问题:

3.巨人和鬼的问题(好算法):

算法分析:

本题属于凸包问题。

我们设P1..Pn为巨人的固定点;Pn+1..P2n为鬼的固定点。我们采取分治采取分治策略寻找序列[Pp..Pr]中的配对方案(初始时[Pp..Pr]为[P1..P2n]):

        在[Pp..Pr]中找出一个最低位置(Y坐标值最小)的一个点P0,如果这样的点有多个,则选取最左边的点为P0,P0与Pp交换。然后将其余点[Pp+1..Pr]按相对 Pp的极角递增的顺序排列。显然Pp与其余点Pp+1..Pr之间的任何线段是不会交叉的。我们从Pp开始寻找一个巨人和鬼成对的最小子区间[Pp..Pi](p≤i≤r)。若该子区间仅剩一个元素,配对结束;否则巨人(鬼)Pp与鬼(巨人)Pi配对。这样使得尚未配对的巨人和鬼分布在两个子区间[Pp+1..Pi-1],[Pi+1..Pr]。继续按上述分治策略分别递归求解[Pp+1..Pi-1]和[Pi+1..Pr]。

《8.3递归与分治》

如上图,以点P1,将其他点按相对P1的极角递增排序。然后从P2开始顺序地找一个最短的配对序列P1-P6(鬼和巨人的个数要相等,这样才能一一配对。P1-P6是3个鬼,3个巨人)。怎样求分割线P1P6呢?是给鬼和巨人一个标志,设鬼为-1,巨人为1,从P2开始找时,逐渐累加,直到为1时停止,表明鬼和人的个数相等,如P1到P2时:2个鬼(-1-1=-2),继续到P3:2鬼1巨人(-1-1+1=-1),P4:3鬼1巨人(-1-1+1-1=-2),P5:3鬼2巨人(-1-1+1-1+1=-1),P6:3鬼3巨人(-1-1+1-1+1+1=0),此时鬼和巨人的个数相等,则分割线为P1P6,将P1-P8分割成(P2-P5)和(P7-P8)。再递归对(P2-P5)和(P7-P8)按同样的方法分治求解。

    原文作者:递归与分治算法
    原文地址: https://blog.csdn.net/glqglqglq2/article/details/38369813
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞