POJ 第三周 编程题#1: 完美覆盖

自己做完之后对比了下网上的解题思路都是归纳出递归式直接求值,这里给出我的一个搜索方法。 思路:

  • 求f(n)使得f(n)能完美覆盖棋盘
  • 棋盘总的格子数目是3*n,因此如果n是奇数,一定不会被完美覆盖
  • 我们假定一直先横向摆放多米诺古牌,如果摆放过那么对他进行标记,横向的就是标记(x,y)与(x+1,y),然后找下一个可能摆放的位置,如果能找到那么继续标记;如果找不到,那么返回到纵向搜索,同时清除这一步之前的所有标记(只需要每次调用递归函数后清除就行了),然后继续搜索;如果还没搜索到那么继续继续上面两个步骤。
  • 伪代码f(x,y) = f(x+2,y) + f(x,y+1)(横向和纵向搜索之和)
  • 退出条件:下一个搜索点的y==3(因为我们始终先横向搜索)
  • 对于横向,只有横向占据的两点(x,y)和(x+1,y)的横纵坐标都分别不大于col与row,并且这两点之前没有没标记过,那么我们继续搜索;否则此次搜索不成立,直接返回;同理对于纵向也是一样
#include <iostream>
#include <vector>
using namespace std;
const int ROW = 3;

struct point{
    int x;
    int y;
};


point nextPoint(char **a,int x, int y,int col,int direct){
    if(direct == 0){  //横向
        x = x+2;
    }else{ //纵向
        x += 1;
    }
    if(x>col-1){
        x = 0;
        y = y+1;
        if(y == ROW){
            point p = {-1,-1};
            return p;
        }
    }
    if(a[y][x] == '_'  || a[y][x] == '|'){
        return nextPoint(a, x, y,col, 1);
    }else{
        point tmp = {x,y};
        return tmp;
    }
}

int total;

void printArr(char **a,int row,int col){
    for(int i=0;i<row;i++){
        for(int j=0;j<col;j++){
            cout<<a[i][j];
        }
        cout<<endl;
    }
    cout<<"next line"<<endl;
}


void func(char **a,int n_x, int n_y, int row, int col,int direc){
    if(n_x == -1){
        total++;
        printArr(a, row, col);
        return;
    }
        //1.水平方向,标记
        if(direc==0){
            if(n_y<row && n_x<col && n_x+1<col &&  a[n_y][n_x] == ' ' && a[n_y][n_x+1] == ' '){
                a[n_y][n_x] = '_';
                a[n_y][n_x+1] = '_';
                point p = nextPoint(a, n_x, n_y, col,-1);
                func(a, p.x, p.y, row,col,-1);
                a[n_y][n_x] = ' ';
                a[n_y][n_x+1] = ' ';
            }else{
                return;
            }
        }
    //竖直方向
    if(direc == 1){
        if(n_x< col && n_y <row && n_y+1<row && a[n_y+1][n_x] ==' ' &&  a[n_y][n_x] == ' '){
            a[n_y+1][n_x] = '|';
            a[n_y][n_x] = '|';
            point p = nextPoint(a, n_x, n_y, col, direc);
            func(a, p.x, p.y, row,col,-1);
            a[n_y+1][n_x] = ' ';
            a[n_y][n_x] = ' ';
        }else{
            return;
        }
    }
    if(direc == -1){
        func(a, n_x, n_y, row, col,0);
        func(a, n_x, n_y, row, col,1);
    }


}

int main(){
    int COL;
    cin>>COL;
    if(COL%2){
        cout<<"不能完美覆盖"<<endl;
        return 0;
    }
    char **a = new char*[ROW];
    for(int i=0;i<ROW;i++){
        a[i] = new char[COL+1];
    }
    //最外层加圈
    for(int i=0;i<ROW;i++){
        for(int j=0;j<COL;j++){
            a[i][j] = ' ';
        }
    }
    //初始方向设置为-1,然后再函数内横向0,纵向1搜索
    func(a, 0, 0, ROW, COL,-1);
    cout<<"total"<<total<<endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值