HNU2019暑期训练赛之7 J. Pinemi Puzzles

Problem Description

A Pinemi Puzzle is a 10-by-10 array of squares with numbers in some of the squares and the other squares left blank.

To solve the puzzle, add 1, 2, or 3 vertical strokes to each blank box so that:

There are exactly 10 strokes in each row
There are exactly 10 strokes in each column
For each box with a number in it, the number in the box is the total number of strokes in neighboring boxes (up, down, right, left, and diagonal).
For this problem, you will write a program to solve Pinemi Puzzles!
在这里插入图片描述

Input

The first line of input contains a single decimal integer P, (1 ≤ P ≤ 100), which is the number of data sets that follow. Each data set should be processed identically and independently.

Each data set consists of 11 lines of input. The first line contains the data set number, K. The following 10 lines each consist of 10 integers separated by spaces. A value of -1 indicates that the box in the puzzle is blank. Otherwise, the value gives the count of neighboring strokes for the box. The ith element of the jth of the 10 input lines describes the box in row j and column i.

Output

For each data set there are 11 lines of output.

The first output line consists of the data set number, K. The following 10 lines of output consist of 10 decimal digits separated by one to six spaces. The value in the jth position in the ith line of the 10 output lines is the input value, if the input value in in the jth position in the ith line was > 0.

Otherwise it is the number of strokes for the (initially blank) box in the jth column in the ith row. Note: For some problems, there may be more than one correct solution. The number of spaces between values is not important, however, padding the numbers out (as shown below in the Sample Output) may make your output more readable and easier to debug.

Sample Input

1
1
-1 9 -1 -1 5 4 -1 5 -1 3
5 -1 -1 -1 8 -1 10 -1 7 -1
2 10 -1 14 -1 -1 -1 -1 9 -1
1 6 -1 -1 -1 12 10 9 -1 -1
-1 8 8 -1 -1 -1 -1 7 -1 -1
-1 -1 6 6 -1 -1 -1 -1 7 4
10 -1 11 -1 9 -1 -1 -1 -1 3
-1 -1 -1 -1 7 5 9 -1 -1 7
-1 9 8 7 -1 6 7 -1 -1 -1
-1 -1 2 -1 -1 -1 -1 6 -1 -1

Sample Output

1
3 9 1 2 5 4 2 5 2 3
5 2 3 1 8 2 10 1 7 1
2 10 2 14 2 1 2 2 9 1
1 6 3 2 1 12 10 9 1 3
1 8 8 1 1 2 3 7 1 1
2 2 6 6 3 1 1 1 7 4
10 2 11 1 9 2 1 2 2 3
1 3 1 2 7 5 9 2 1 7
2 9 8 7 2 6 7 2 2 2
1 1 2 1 1 2 1 6 1 2

Solution

 枚举每行相加可能等于10的情况,dfs

核心:1.打表列举可能的情况
在这里插入图片描述
2.inline bool next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last)

在这里插入图片描述

遗憾的是没能在结束前写完代码。。

AC Code

#include <bits/stdc++.h>

using namespace std;
int board[10][10];
int direction[8][2] = {{-1, -1},
                       {0,  1},
                       {1,  -1},
                       {-1, 0},
                       {1,  0},
                       {-1, 1},
                       {0,  -1},
                       {1,  1}};

bool inBound(int x, int y) {
    return !(x < 0 || x > 9 || y < 0 || y > 9);
}

int table[11][11][11];
static int stable[11][11][11] = {{{0},                            {0}},
                                 {{0},                            {0}},
                                 {{0},                            {0}},
                                 {{0},                            {0}},
                                 {{1, 3, 3, 3},                   {2, 2, 3, 3},             {0}},
                                 {{1, 1, 2, 3, 3},                {1, 2, 2, 2, 3},          {2, 2, 2, 2, 2},    {0}},
                                 {{1, 1, 1, 1, 3, 3},             {1, 1, 1, 2, 2, 3},       {1, 1, 2, 2, 2, 2}, {0}},
                                 {{1, 1, 1, 1, 1, 2, 3},          {1, 1, 1, 1, 2, 2, 2},    {0}},
                                 {{1, 1, 1, 1, 1, 1, 1, 3},       {1, 1, 1, 1, 1, 1, 2, 2}, {0}},
                                 {{1, 1, 1, 1, 1, 1, 1, 1, 2},    {0}},
                                 {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {0}}};

int emptyNumOfRow[11];
int strokes[10][10];

void deliver(const int *a, int num, int row) {
    int cnt = 0;
    for (int i = 0; i < 10; ++i) {
        if (board[row][i] == -1)
            strokes[row][i] = a[cnt++];
        if (cnt >= num)
            break;
    }
}

bool testRow(int row) {
    for (int j = 0; j < 10; ++j) {
        if (board[row][j] != -1) {
            int sum = 0;
            for (auto &dir : direction) {
                int dx = dir[0];
                int dy = dir[1];
                int x = row + dx;
                int y = j + dy;
                if (inBound(x, y)) {
                    sum += strokes[x][y];
                }
            }
            if (sum != board[row][j])
                return false;
        }
    }
    return true;
}

bool allTest() {
    for (int j = 0; j < 10; ++j) {
        int sum = 0;
        for (auto &stroke : strokes)
            sum += stroke[j];
        if (sum != 10)
            return false;
    }
    return true;
}

bool dfs(int row) {
    if (row == 10) {
        if (!testRow(row - 1))
            return false;
        return allTest();
    }
    int empNum = emptyNumOfRow[row];
    for (int way = 0; way < 3; ++way) {
        int tb[11];
        memcpy(tb, stable[empNum][way], sizeof(tb));
        if (tb[0] == 0)
            break;
        do {
            deliver(tb, empNum, row);
            if (row != 0) {
                if (!testRow(row - 1))
                    continue;
            }
            if (dfs(row + 1))
                return true;
        } while (next_permutation(tb, tb + empNum));
    }
    return false;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int caseNum;
        cin >> caseNum;
        memcpy(table, stable, sizeof(table));
        memset(strokes, 0, sizeof(strokes));
        memset(emptyNumOfRow, 0, sizeof(emptyNumOfRow));

        for (int i = 0; i < 10; ++i) {
            for (int j = 0; j < 10; ++j) {
                cin >> board[i][j];
                if (board[i][j] == -1)
                    emptyNumOfRow[i]++;
            }
        }
        dfs(0);

        printf("%d\n", caseNum);
        for (int i = 0; i < 10; ++i) {
            for (int j = 0; j < 10; ++j) {
                if (board[i][j] == -1)
                    printf("%d", strokes[i][j]);
                else printf("%d", board[i][j]);
                if (j != 9)
                    putchar(' ');
            }
            putchar('\n');
        }
    }

    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值