P1074 [NOIP2009 提高组] 靶形数独(搜索剪枝)

题目大意:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解题思路:

这题不难,但是学到了一个特别实用的搜索小技巧:先从状态少的开始搜索

  • 因为搜索树上虽然节点个数相同剪枝会剪掉更多的节点。
    感性理解一下,如果在某个地方存在剪枝,把情况较多的节点放在它后面枚举显然比放在前面快

AC代码:

#include <bits/stdc++.h>
using namespace std;
int cnt, ans = -1;
int a[10][10], row[10][10], column[10][10], pal[10][10], zp[100][4];
struct P {
    int row, sum;
} zero[10];
bool cmp(P lhs, P rhs) {return lhs.sum < rhs.sum;}
int _pal(int tx, int ty) {
    if (1 <= tx && tx <= 3) {
        if (1 <= ty && ty <= 3) return 1;
        else if (4 <= ty && ty <= 6) return 2;
        else return 3;
    }
    else if (4 <= tx && tx <= 6) {
        if (1 <= ty && ty <= 3) return 4;
        else if (4 <= ty && ty <= 6) return 5;
        else return 6;
    }
    else {
        if (1 <= ty && ty <= 3) return 7;
        else if (4 <= ty && ty <= 6) return 8;
        else return 9;        
    }
}
int _point(int tx, int ty) {
    if (tx == 1 || ty == 1 || tx == 9 || ty == 9) return 6;
    else if (tx == 2 || ty == 2 || tx == 8 || ty == 8) return 7;
    else if (tx == 3 || ty == 3 || tx == 7 || ty == 7) return 8;
    else if (tx == 4 || ty == 4 || tx == 6 || ty == 6) return 9;
    else return 10;
}
void dfs(int num, int sum) {
    if (num == cnt + 1) {
        ans = max(ans, sum);
        return;
    }
    for (int i = 1; i <= 9; i++) {
        if (!row[zp[num][0]][i] && !column[zp[num][1]][i] && !pal[zp[num][3]][i]) {
            row[zp[num][0]][i] = column[zp[num][1]][i] = pal[zp[num][3]][i] = 1;
            dfs(num + 1, sum + i * zp[num][2]);
            row[zp[num][0]][i] = column[zp[num][1]][i] = pal[zp[num][3]][i] = 0;
        }
    }
    return;
}
int main() {
    int sum = 0;
    for (int i = 1; i <= 9; i++) zero[i].row = i;
    for (int i = 1; i <= 9; i++)
        for (int j = 1; j <= 9; j++) {
            cin >> a[i][j];
            if (a[i][j]) {
                row[i][a[i][j]] = column[j][a[i][j]] = pal[_pal(i, j)][a[i][j]] = 1, sum += _point(i, j) * a[i][j];    
            }
            else
                zero[i].sum++;
        }
    sort (zero  + 1, zero + 9 + 1, cmp);
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= 9; j++) {
            if (a[zero[i].row][j]) continue;
            zp[++cnt][0] = zero[i].row, zp[cnt][1] = j, zp[cnt][2] = _point(zero[i].row, j), zp[cnt][3] = _pal(zero[i].row, j);
        }
    }
    dfs(1, sum);
    cout << ans << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值