zoukankan      html  css  js  c++  java
  • [C++] 分治法之棋盘覆盖、循环赛日程表

    一、分治的基本思想

      将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。

      对于一个规模为 n 的问题,若问题可以容易地解决,则直接解决,否则将其分解为 k 个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。

    二、用分治法求解问题的主要步骤

      1、分解:将原问题分解为若干规模较小、相互独立、与原问题形式相同的子问题;

      2、解决:若子问题规模较小而容易被解决则直接解决,否则,递归地解各个子问题;

      3、合并:将各子问题的解合并得到原问题的解。

    三、分治法实例

      1、棋盘覆盖

      在一个 2k * 2个方格组成的棋盘中,有一个方格与其它的不同,若使用以下四种 L 型骨牌覆盖除这个特殊方格的其它方格,如何覆盖。四个 L 型骨牌如下图:

    图1.1 L型骨牌

           棋盘中的特殊方格如图:

    图1.2 存在特殊方格的棋盘
      覆盖完成后的棋盘:
    图1.3 覆盖完成的棋盘
     1 #include<iostream>
     2 using namespace std;
     3 
     4 int tile = 0;
     5 int Board[4][4];    //棋盘 
     6 
     7 /*
     8 tr:棋盘左上角方格的行号 
     9 tc:棋盘左上角方格的列号
    10 dr:特殊方格所在的行号 
    11 dc:特殊方格所在的列号
    12 size:棋盘的规格(size * size)
    13 */
    14 void ChessBoard(int tr,int tc , int dr, int  dc, int size)
    15 {
    16     if(size == 1) return;
    17     int t =tile++,        //L型骨牌号 
    18         s = size/2;        //分割棋盘 
    19     //覆盖左上角子棋盘 
    20     if(dr < tr+s && dc < tc+s)
    21         //特殊方格在此棋盘中 
    22         ChessBoard(tr,tc,dr,dc,s);
    23     else
    24     {    //此棋盘中无特殊方格
    25         //用t号L型骨牌覆盖右下角 
    26         Board[tr+s-1][tc+s-1] = t;
    27         //覆盖其余方格 
    28         ChessBoard(tr,tc,dr,dc,s);
    29     }
    30     
    31     //覆盖右上角子棋盘
    32     if(dr < tr+s && dc >= tc+s)
    33         //特殊方格在此棋盘中
    34         ChessBoard(tr,tc+s,dr,dc,s);
    35     else
    36     {    //此棋盘中无特殊方格
    37         //用t号L型骨牌覆盖左下角
    38         Board[tr+s-1][tc+s] = t;
    39         //覆盖其余方格 
    40         ChessBoard(tr,tc+s,tr+s-1,tc+s,s);
    41     }
    42     
    43     //覆盖左下角子棋盘
    44     if(dr >= tr+s && dc < tc+s)
    45         //特殊方格在此棋盘中
    46         ChessBoard(tr+s,tc,dr,dc,s);
    47     else
    48     {    //此棋盘中无特殊方格
    49         //用t号L型骨牌覆盖右上角
    50         Board[tr+s][tc+s-1] = t;
    51         //覆盖其余方格 
    52         ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
    53     }
    54     
    55     //覆盖右下角子棋盘
    56     if(dr >= tr+s && dc >= tc+s)
    57         //特殊方格在此棋盘中
    58         ChessBoard(tr+s,tc+s,dr,dc,s);
    59     else
    60     {    //此棋盘中无特殊方格
    61         //用t号L型骨牌覆盖左上角
    62         Board[tr+s][tc+s] = t;
    63         //覆盖其余方格 
    64         ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
    65     }
    66 
    67 }
    68 
    69 int main()
    70 {
    71     ChessBoard(0 , 0 , 1 , 3 , 4);
    72     //输出覆盖完成后的棋盘
    73     for(int i = 0 ; i < 4; i++)
    74     {
    75         for(int j = 0 ; j < 4; j++)
    76         {
    77             cout<<Board[i][j];
    78         }
    79         cout<<endl;
    80     }
    81     return 0;
    82 }

      2、循环赛日程表

      设有 n = 2个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:

        (1)每个选手必须与其他n-1个选手各赛一次;

        (2)每个选手一天只能参赛一次;

        (3)循环赛在n-1天内结束

         请按此要求将比赛日程表设计成有 n 行和 n-1 列的一个表。在表中的第 i 行,第 j 列处填入第 i 个选手在第 j 天所遇到的选手。其中 1 ≤ i ≤ n,1 ≤ j ≤ n-1。8 个选手的比赛日程表如下图:

     1 #include<iostream>
     2 using namespace std;
     3 
     4 int a[100][100];
     5 int n;    //选手的个数
     6 
     7 /*
     8 tox:目标数组的行号 
     9 toy:目标数组的列号 
    10 fromx:源数组的行号 
    11 fromy:源数组的列号 
    12 r:数组的大小为 r*r 
    13 */
    14 void Copy(int tox, int toy, int fromx, int fromy, int r)
    15 {
    16     for(int i = 0; i < r; i++)
    17         for(int j = 0; j < r; j++)  
    18             a[tox+i][toy+j] = a[fromx+i][fromy+j];
    19 }
    20 
    21 void Table(int k)
    22 {    
    23     n = 1 << k;    
    24     //构造正方形表格的第一行数据
    25     for(int i = 0; i < n; i++)
    26         a[0][i] = i + 1;
    27     //采用分治算法,构造整个循环赛日程表
    28     for(int r = 1; r < n; r <<= 1)
    29         for(int i = 0; i < n; i += 2*r)
    30         { 
    31             Copy(r, r + i, 0, i, r);        //左上角复制到右下角 
    32             Copy(r, i, 0, r + i, r);        //右上角复制到左下角 
    33         }
    34 }
    35 
    36 
    37 int main()
    38 {
    39     int k;
    40     cout<<"请输入k的值:";
    41     cin>>k; 
    42     
    43     Table(k);
    44     
    45     for(int i = 0; i < n; i++)
    46     {
    47         for(int j = 0; j < n; j++)
    48         {
    49             cout<< a[i][j] << " ";
    50         }
    51         cout<<endl;
    52     } 
    53     return 0;
    54 }
  • 相关阅读:
    OCP-1Z0-053-V13.02-498题
    Oracle索引扫描算法
    dojo CsvStore简介
    Oracle预估的基数算法
    HTML多表头表格
    hql查询实例
    PGA突破pga_aggregate_target限制
    OCP-1Z0-053-V13.02-330题
    java 发送字节流图片,c++接收二进制流
    windows 7蓝屏解决办法
  • 原文地址:https://www.cnblogs.com/cao-lei/p/6891648.html
Copyright © 2011-2022 走看看