【笔记】《算法竞赛入门》习题7-6 UVa12113_重叠的正方形
阅读原文时间:2023年07月08日阅读:2

title: 习题7-6 UVa12113_重叠的正方形

date: 2021-01-31 19:08:00

categories:

  • 算法竞赛入门

tags:

  • 数据结构
  • 算法
  • UVa

思路:

题目要求用6个长为2的正方形描绘输入的正方形边缘,如果可以描绘,输出yes,否则no

我用一个三维数组描述图形,比如G[i][j][k]表示以i,j点上k方向有边,k取值为0或者1,分别表示右和下

dfs函数设计为寻找遍历路径上没有被遍历过的点作为左上角描绘一个正方形,如果深度大于6返回false

如果通过judge则返回true,如果叶子返回true,也返回true,具体页末看代码,代码结构清晰

原题:

[UVA-12113][https://vjudge.net/problem/UVA-12113]

//
// Created by hsby on 2021/1/31.
//

#include <iostream>
#include <cstring>
using namespace std;

const int maxn = 5;

enum {RIGHT = 0, DOWN = 1};
int G[maxn][maxn][2];
int GT[maxn][maxn][2];
int vis[maxn-1][maxn-1];

bool judge(){
    for (int i = 0; i < maxn; ++i) {
        for (int j = 0; j < maxn; ++j) {
            for (int k = 0; k < 2; ++k) {
                if (G[i][j][k] && !GT[i][j][k]){
                    return false;
                }
            }
        }
    }
    return true;
}

void draw(int x, int y){
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            // 描绘水平方向的边
            if (i != 1 && j < 2) GT[x+i][y+j][RIGHT] += 1;
            // 描绘竖直方向的边
            if (j != 1 && i < 2) GT[x+i][y+j][DOWN] += 1;
        }
    }
}

void erase(int x, int y){
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (i != 1 && j < 2) GT[x+i][y+j][RIGHT] -= 1;
            if (j != 1 && i < 2) GT[x+i][y+j][DOWN] -= 1;
        }
    }
}

bool dfs(int x, int y, int d){
    if (judge()) return true;
    if (d > 6) {
        return false;
    }
    for (int i = 0; i < maxn-2; ++i) {
        for (int j = 0; j < maxn-2; ++j) {
            if (vis[i][j]) continue;
            vis[i][j] = 1;
            draw(i, j);
            if (dfs(i, j, d+1)) return true;
            erase(i, j);
            vis[i][j] = 0;
        }
    }
    return false;
}

int main(){

    int T = 1;
    string line;
    while (cin.peek() != '0'){
        memset(G, 0, sizeof(G));
        memset(GT, 0, sizeof(GT));
        memset(vis, 0, sizeof(vis));
        for (int i = 0; i < maxn; ++i) {
            getline(cin, line);
            for (int j = 0; line[j] != '#'; ++j) {
                int tj = j/2;
                if (line[j] == '|'){
                    G[i-1][tj][DOWN] = 1;
                }
                if (line[j] == '_'){
                    G[i][tj][RIGHT] = 1;
                }
            }
        }
        printf("CASE %d: ", T++);
        if (dfs(0, 0, 1)) cout << "Yes" << endl;
        else cout << "No" << endl;
    }

    return 0;
}