「刷题记录」LOJ/一本通提高篇 深搜的剪枝技巧
「数的划分」
题目传送门:数的划分
思路:确定下限,每一次搜的数都不能小于前一次,同时,上限就是不能超出范围
点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
int n, k, ans;
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
void dfs(int las, int sum, int cnt)
{
if(cnt == k) {
if(sum == n) {
++ans;
}
return ;
}
for (int i = las; sum + i * (k - cnt) <= n; ++i) {
dfs(i, sum + i, cnt + 1);
}
}
int main() {
n = read(), k = read();
if(n == k) {
printf("1\n");
return 0;
}
dfs(1, 0, 0);
printf("%d\n", ans);
return 0;
}
「生日蛋糕」
题目传送门:生日蛋糕
思路:预处理出最小体积与面积,如果当前面积加上剩下还没涂的蛋糕的最小面积比最优解大,直接返回,如果当前体积加上剩下的蛋糕的最小体积已经超过 \(n\),直接返回
圆柱体侧面积公式: \(S = 2 \times \pi \times r \times h\)
圆柱体体积公式: \(V = \pi \times r^2 \times h\)
体积转化成面积公式为: \(V \times 2 \div r = S\)
如果剩余的体积转化成的面积加上原有的面积比最优解大,直接返回
枚举高时,我们可以确定下限,第 \(i\) 层的高的下限就是 \(i\)
上代码:
点击查看代码
/*
date:2022.8.12
worked by yi_fan0305
*/
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 30;
const int inf = ~(1 << 31);
int n, m, ans = inf;
int r[N], h[N], mins[N], minv[N];
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
void dfs(int rest, int r, int h, int s, int v) {// rest 还剩多少层 r 半径 h 高 s 面积 v 体积
if (rest == 0) { // 到达最顶层,判断走人
if (v == n) { // 体积等于n
ans = min(ans, s);
}
return ;
}
if (s + mins[rest - 1] >= ans)
return ;
// 如果当前求出的面积已经不满足最优解了,直接return
if (v + minv[rest - 1] > n)
return ;
// 如果当前求出的体积已经不满足最优解了,直接return
if (s + 2 * (n - v) / r >= ans)
return ;
// 如果当前求出的面积+公式推出的剩余部分的面积已经大于最优解,直接return
for (int rr = r - 1; rr >= rest; --rr) {
if (rest == m) {
s = rr * rr;//预处理出每层蛋糕上表面要涂的面积
}
int maxh = min(h - 1, (n - minv[rest - 1] - v) / rr / rr);// 处理当前这一层的高
for (int hh = maxh; hh >= rest; --hh) {
dfs(rest - 1, rr, hh, s + 2 * rr * hh, v + rr * rr * hh);//继续向下搜索
}
}
}
int main() {
n = read();
m = read();
for (int i = 1; i <= m; ++i) {
mins[i] = mins[i - 1] + 2 * i * i;// 预处理出最小面积
minv[i] = minv[i - 1] + i * i * i;// 预处理出最小体积
}
dfs(m, n, n, 0, 0);//m 剩余层数 n 半径 n 高 0 面积 0 体积
if (ans == inf)
printf("0\n");
else
printf("%d\n", ans);
return 0;
}
「小木棍」
题目传送门:小木棍
很经典的题目,不会的看一下这篇博客 大佬的博客
代码:
点击查看代码
/*
date:2022.8.28
worked by yi_fan0305
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
typedef long long ll;
using namespace std;
const int N = 70;
int n, sum, m, fg, le;
int len[N], nxt[N], vis[N];
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
int cmp(int a, int b) {
return a > b;
}
void dfs(int cur, int las, int re) {
if(!re) {
if(cur == m) {
fg = 1;
return ;
}
int i;
for (i = 1; vis[i] && i <= n; ++i);
vis[i] = 1;
dfs(cur + 1, i, le - len[i]);
vis[i] = 0;
if(fg) return ;
}
int l = las + 1, r = n, mid;
while (l < r) {
mid = (l + r) >> 1;
if(len[mid] <= re) r = mid;
else l = mid + 1;
}
for (int i = l; i <= n; ++i) {
if(!vis[i]) {
vis[i] = 1;
dfs(cur, i, re - len[i]);
vis[i] = 0;
if(fg) return ;
if(re == len[i] || re == le) return ;
i = nxt[i];
if(i == n) return ;
}
}
}
int main() {
n = read();
for (int i = 1; i <= n; ++i) {
len[i] = read();
sum += len[i];
}
sort(len + 1, len + n + 1, cmp);
nxt[n] = n;
for (int i = n - 1; i; --i) {
(len[i] == len[i + 1]) ? nxt[i] = nxt[i + 1] : nxt[i] = i;
}
int maxup = sum >> 1;
fg = 0;
for (le = len[1]; le <= maxup; ++le) {
if(sum % le) continue;
m = sum / le;
vis[1] = 1;
dfs(1, 1, le - len[1]);
vis[1] = 0;
if(fg) {
printf("%d\n", le);
return 0;
}
}
printf("%d\n", sum);
return 0;
}
「Addition Chains」
题目传送门:Addition Chains
思路:这应该是迭代加深搜索,限制深度,如果当然搜到的深度比之前搜到的最优深度要大,直接返回
设当前层为 \(x\),还剩 \(d\) 层,当前层的数为 \(a\),下一层的数为 \(b\),那么 \(b \le 2 \times a\)
为什么?因为最差情况就是 \(2\) 个 \(a\) 相加,又因为还剩 \(d\) 层,所以最差情况下最后一个数字为 \(a \times 2 ^ d\)
如果 \(a \times 2 ^ d < n\) 直接返回即可
代码:
点击查看代码
/*
date: 2022.8.28
worked by yi_fan0305
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
typedef long long ll;
using namespace std;
const int N = 10005;
const int inf = ~(1 << 31);
int n, maxup;
int a[N], ans[N];
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
void dfs(int dep) {
if (dep - 1 > maxup)
return ;
if (a[dep - 1] > n)
return ;
if ((ll)a[dep - 1] * (1ll << (maxup - dep)) < n)
return ;
if (a[dep - 1] == n) {
if ((dep - 1) > maxup)
return ;
maxup = dep - 1;
for (int i = 1; i <= maxup; ++i) {
ans[i] = a[i];
}
}
else {
for (int i = dep - 1; i; --i) {
if (a[dep - 1] + a[i] <= n) {
a[dep] = a[dep - 1] + a[i];
dfs(dep + 1);
a[dep] = 0;
}
}
}
}
int main() {
while (1) {
n = read();
if (!n)
return 0;
if (n == 1) {
printf("1\n");
continue;
}
maxup = inf;
a[1] = 1;
dfs(2);
for (int i = 1; i <= maxup; ++i) {
printf("%d", ans[i]);
if (i != maxup)
printf(" ");
}
printf("\n");
}
return 0;
}
「weight」
题目传送门:weight
思路:说白了,就是前缀和和后缀和顺序打乱了,先将数字按升序排序,最大的两个是左右数字的和,先排除掉,最小的两个,一定为队首和队尾,但具体谁在前谁在后,我们只能搜一下,剩下的数,可能是前缀和,也可能是后缀和,我们需要进行搜索,具体看代码吧
代码:
点击查看代码
/*
date: 2022.8.28
worked by yi_fan0305
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1010;
const int M = 5e5 + 5;
int n, m, sum, fg;
int a[N << 1], s[M], ans[N];
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
void dfs(int cur, int l, int r, int lval, int rval) {
if (fg)
return ;
if (l == r) {
if (!(s[a[cur] - lval] || s[a[cur] - rval]))
return ;
int tmp = a[n << 1] - lval - rval;
if(tmp < 1 || tmp > 500)
return ;
ans[l] = tmp;
fg = 1;
for (int i = 1; i <= n; i ++)
printf("%d ", ans[i]);
return ;
}
if (s[a[cur] - lval]) {
ans[l] = a[cur] - lval;
dfs(cur + 1, l + 1, r, a[cur], rval);
}
if (s[a[cur] - rval]) {
ans[r] = a[cur] - rval;
dfs(cur + 1, l, r - 1, lval, a[cur]);
}
}
int main() {
n = read();
int nn = n << 1;
for (int i = 1; i <= nn; ++i) {
a[i] = read();
}
m = read();
for (int i = 1; i <= m ; ++i) {
int x = read();
s[x] = 1;
}
sort(a + 1, a + nn + 1);
ans[1] = a[1];
sum = a[nn];
dfs(1, 1, n, 0, 0);
return 0;
}
「埃及分数」
题目传送门:埃及分数
思路:迭代加深搜索
剪枝1:每次分母都要比前一次大,设 \(pre\) 为前一次搜到的分母,下一次就可以从pre + 1开始
优化2:
\(\frac{1}{a} < \frac{mol}{den}\)
\(den < mol \times a\)
\(a > \frac{den}{mol}\)
每一次搜索,分母也可以从当前还剩分数的倒数开始
优化3: 还剩 \((lim + 1 - dep)\) 个数
设 \(x = (lim + 1 - dep)\)
最差情况是每个数都等于 \(\frac{\frac{mol}{den}}{x}\)
\(\frac{\frac{mol}{den}}{x} = \frac{mol}{den \times x} = \frac{1}{den \times x \div mol}\)
所以每次搜索分母的上限就是 \(den \times x \div mol\)
从小到大枚举搜索深度,直接开搜
代码:
点击查看代码
/*
date: 2022.8.29
worked by yi_fan0305
*/
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int inf = ~(1 << 31);
const int N = 1010;
ll a, b, fg, ans, lim;
ll tot[N], num[N];
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
void dfs(ll dep, ll mol, ll den, ll pre) {
if (dep == lim + 1) {
if (!mol) {
fg = 1;
if (num[lim] < tot[lim]) {
for (ll i = 1; i <= lim; ++i) {
tot[i] = num[i];
}
ans = num[lim];
}
}
return ;
}
// 优化1:每次分母都要比前一次大,可以从pre + 1开始
// 优化2: 1 / a < mol / den
// den < mol * a
// a > den / mol
// 优化3: 还剩(lim + 1 - dep)个数,最差情况是每个数都等于 (mol / den) / x
// (mol / den) / x = mol / (den * x) = 1 / (den * x / mol)
int x = (lim + 1 - dep);
for (ll i = max(pre + 1, den / mol); i <= den * x / mol; ++i) {
num[dep] = i;
dfs(dep + 1, mol * i - den, den * i, i);
}
}
int main() {
a = read();
b = read();
for (lim = 1; ; ++lim) {
tot[lim] = inf;
ans = inf;
dfs(1, a, b, 1);
if(fg)
break;
}
for(int i = 1; i < lim; ++i) {
printf("%lld ", tot[i]);
}
printf("%lld\n", tot[lim]);
return 0;
}
「平板涂色」
题目传送门:平板涂色
说实话,不是很有技术含量
思路:每次枚举,判断哪些矩形已经符合被染色的条件,符合后,如果矩形的颜色与当前颜色相同,不用换刷子,否则,换刷子次数 \(+1\),如果次数已经比最优解大了,直接返回,最优性剪枝
代码:
点击查看代码
/*
date: 2022.8.29
worked by yi_fan0305
*/
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
int n, ans = ~(1 << 31);
int vis[20], cnt[20];
struct matx {
int xl, yl, xr, yr, col;
vector<int> up;
} mat[20];
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
void dfs(int tot, int fin, int col) {
if (fin == n) {
ans = min(ans, tot);
return ;
}
if (tot >= ans) return ;
for (int i = 1; i <= n; ++i) {
if(!vis[i] && !cnt[i]) {
vis[i] = 1;
int siz = mat[i].up.size();
for (int j = 0; j < siz; ++j) {
--cnt[mat[i].up[j]];
}
if(mat[i].col == col)
dfs(tot, fin + 1, col);
else
dfs(tot + 1, fin + 1, mat[i].col);
vis[i] = 0;
for (int j = 0; j < siz; ++j) {
++cnt[mat[i].up[j]];
}
}
}
}
int main() {
n = read();
for (int i = 1; i <= n; ++i) {
mat[i].xl = read();
mat[i].yl = read();
mat[i].xr = read();
mat[i].yr = read();
mat[i].col = read();
}
for (int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
if (mat[j].xl != mat[i].xr) continue;
if (i == j || mat[i].yl >= mat[j].yr || mat[i].yr <= mat[j].yl) continue;
mat[i].up.push_back(j);
++cnt[j];
}
}
dfs(0, 0, 0);
printf("%d\n", ans);
return 0;
}
「质数方阵」
题目传送门:质数方阵
感觉像模拟。。。
直接上代码吧,这题让我有点崩溃
点击查看代码
/*
date: 2022.8.29
worked by yi_fan0305
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#define A a[cnt]
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int sum, n, m, cnt = 1;
int a[10010][8][8];
string ans[10010];
int vis[N + 10];
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
int calc(int a1, int a2, int a3, int a4, int a5) {
return (a1 * 10000 + a2 * 1000 + a3 * 100 + a4 * 10 + a5);
}
int check(int x) {
int t = sqrt(x);
for (int i = 2; i <= t; ++i) {
if (x % i == 0)
return 0;
}
return 1;
}
void make_prime() {
for (int i1 = 1; i1 <= 9; ++i1) {
for (int i2 = 0; i2 <= 9; ++i2) {
for (int i3 = 0; i3 <= 9; ++i3) {
for (int i4 = 0; i4 <= 9; ++i4) {
for (int i5 = 1; i5 <= 9; ++i5) {
int t = calc(i1, i2, i3, i4, i5);
if ((i1 + i2 + i3 + i4 + i5 == sum) && check(t))
vis[t] = 1;
}
}
}
}
}
}
void qsort(int l, int r) {
int i = l, j = r;
string mid = ans[(l + r) >> 1];
do {
while (ans[i] < mid)
++i;
while (ans[j] > mid)
--j;
if (i <= j) {
swap(ans[i], ans[j]);
++i;
--j;
}
} while (i <= j);
if (l < j)
qsort(l, j);
if (i < r)
qsort(i, r);
}
void print() { //输出答案
--cnt;
if (cnt == 0) {
printf("NONE");
return ;
}
for (int i = 1; i <= cnt; ++i) {
for (int j = 1; j <= 5; ++j) {
for (int k = 1; k <= 5; ++k)
ans[i] = ans[i] + (char)(a[i][j][k] + 48);
}
}
qsort(1, cnt);
for (int i = 1; i <= cnt; ++i) {
for (int j = 0; j <= 20; j += 5) {
for (int k = j; k < j + 5; ++k)
putchar(ans[i][k]);
printf("\n");
}
printf("\n");
}
}
void dfs13() {
for (int i = 1; i <= 9; i += 2) {
A[5][3] = i;
A[5][4] = sum - A[5][1] - A[5][2] - A[5][3] - A[5][5];
if (A[5][4] < 0 || A[5][4] > 9)
continue;
int t1 = calc(A[5][1], A[5][2], A[5][3], A[5][4], A[5][5]);
if (!vis[t1])
continue;
A[1][3] = sum - A[2][3] - A[3][3] - A[4][3] - A[5][3];
if (A[1][3] < 0 || A[1][3] > 9)
continue;
int t2 = calc(A[1][3], A[2][3], A[3][3], A[4][3], A[5][3]);
if (!vis[t2])
continue;
A[1][4] = sum - A[1][1] - A[1][2] - A[1][3] - A[1][5];
if (A[1][4] < 0 || A[1][4] > 9)
continue;
int t3 = calc(A[1][1], A[1][2], A[1][3], A[1][4], A[1][5]);
if (!vis[t3])
continue;
if (A[1][4] + A[2][4] + A[3][4] + A[4][4] + A[5][4] != sum)
continue;
int t4 = calc(A[1][4], A[2][4], A[3][4], A[4][4], A[5][4]);
if (!vis[t4])
continue;
++cnt;
for (int j = 1; j <= 5; ++j) {
for (int k = 1; k <= 5; ++k)
A[j][k] = a[cnt - 1][j][k];
}
}
}
void dfs12() {
for (int i = 1; i <= 9; i += 2) {
A[5][2] = i;
A[1][2] = sum - A[2][2] - A[3][2] - A[4][2] - A[5][2];
if (A[1][2] < 0 || A[1][2] > 9)
continue;
int t = calc(A[1][2], A[2][2], A[3][2], A[4][2], A[5][2]);
if (vis[t])
dfs13();
}
}
void dfs11() {
for (int i = 1; i <= 9; i += 2) {
A[3][5] = i;
A[4][5] = sum - A[1][5] - A[2][5] - A[3][5] - A[5][5];
if (A[4][5] < 0 || A[4][5] > 9)
continue;
int t1 = calc(A[1][5], A[2][5], A[3][5], A[4][5], A[5][5]);
if (!vis[t1])
continue;
A[3][2] = sum - A[3][1] - A[3][3] - A[3][4] - A[3][5];
if (A[3][2] < 0 || A[3][2] > 9)
continue;
int t2 = calc(A[3][1], A[3][2], A[3][3], A[3][4], A[3][5]);
if (!vis[t2])
continue;
A[4][3] = sum - A[4][1] - A[4][2] - A[4][4] - A[4][5];
if (A[4][3] < 0 || A[4][3] > 9)
continue;
int t3 = calc(A[4][1], A[4][2], A[4][3], A[4][4], A[4][5]);
if (!vis[t3])
continue;
dfs12();
}
}
void dfs10() {
for (int i = 0; i <= 9; ++i) {
A[3][4] = i;
dfs11();
}
}
void dfs9() {
for (int i = 1; i <= 9; i += 2) {
A[1][5] = i;
A[4][2] = sum - A[1][5] - A[2][4] - A[3][3] - A[5][1];
if (A[4][2] < 0 || A[4][2] > 9)
continue;
int t = calc(A[5][1], A[4][2], A[3][3], A[2][4], A[1][5]);
if (vis[t])
dfs10();
}
}
void dfs8() {
for (int i = 1; i <= 9; i += 2) {
A[2][5] = i;
A[2][3] = sum - A[2][1] - A[2][2] - A[2][4] - A[2][5];
if (A[2][3] < 0 || A[2][3] > 9)
continue;
int t = calc(A[2][1], A[2][2], A[2][3], A[2][4], A[2][5]);
if (vis[t]) dfs9();
}
}
void dfs7() {
for (int i = 0; i <= 9; ++i) {
A[2][4] = i;
dfs8();
}
}
void dfs6() {
for (int i = 1; i <= 9; ++i) {
A[2][1] = i;
A[3][1] = sum - A[1][1] - A[2][1] - A[4][1] - A[5][1];
if (A[3][1] < 0 || A[3][1] > 9)
continue;
int t = calc(A[1][1], A[2][1], A[3][1], A[4][1], A[5][1]);
if (vis[t]) dfs7();
}
}
void dfs5() {
for (int i = 1; i <= 9; ++i) {
A[4][1] = i;
dfs6();
}
}
void dfs4() {
for (int i = 1; i <= 9; i += 2) {
A[5][1] = i;
dfs5();
}
}
void dfs3() {
for (int i = 0; i <= 9; ++i) {
A[2][2] = i;
A[3][3] = sum - A[1][1] - A[2][2] - A[4][4] - A[5][5];
if (A[3][3] < 0 || A[3][3] > 9)
continue;
int t = calc(A[1][1], A[2][2], A[3][3], A[4][4], A[5][5]);
if (vis[t])
dfs4();
}
}
void dfs2() {
for (int i = 0; i <= 9; ++i) {
A[4][4] = i;
dfs3();
}
}
void dfs1() {
for (int i = 1; i <= 9; i += 2) {
A[5][5] = i;
dfs2();
}
}
int main() {
sum = read();
a[1][1][1] = read();
make_prime();
dfs1();
print();
return 0;
}
「靶形数独」
题目传送门:靶形数独
思路:感觉像一个变了形的八皇后,只不过还要处理所在的宫和当前格子的分数,搜索时按行来搜,先从 \(0\) 的个数少的行来搜
代码:
点击查看代码
/*
date: 2022.8.30
worked by yi_fan0305
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
int tot, cnt, ans = -1;
int a[10][10], no[100][4];
int hang[10][10] = {0}, lie[10][10] = {0}, ge[10][10] = {0};
struct node {
int id, sum;
} h[10];
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
int where(int x, int y) {
if (x <= 3) {
if (y <= 3)
return 1;
if (y > 3 && y <= 6)
return 2;
if (y > 6 && y <= 9)
return 3;
}
if (x > 3 && x <= 6) {
if (y <= 3)
return 4;
if (y > 3 && y <= 6)
return 5;
if (y > 6 && y <= 9)
return 6;
}
if (x > 6 && x <= 9) {
if (y <= 3)
return 7;
if (y > 3 && y <= 6)
return 8;
if (y > 6 && y <= 9)
return 9;
}
return 0;
}
int point(int x, int y) {
if (x == 1 || x == 9 || y == 1 || y == 9)
return 6;
if (x == 2 || x == 8 || y == 2 || y == 8)
return 7;
if (x == 3 || x == 7 || y == 3 || y == 7)
return 8;
if (x == 4 || x == 6 || y == 4 || y == 6)
return 9;
return 10;
}
int cmp (node a, node b) {
return a.sum < b.sum;
}
void dfs(int fin, int s) {
if (fin == cnt) {
ans = max(ans, s);
// cout << "*" << endl;
return ;
}
for (int i = 1; i <= 9; ++i) {
int x = no[fin + 1][0], y = no[fin + 1][1];
int g = no[fin + 1][2], pi = no[fin + 1][3];
if (!hang[x][i] && !lie[y][i] && !ge[g][i]) {
hang[x][i] = lie[y][i] = ge[g][i] = 1;
dfs(fin + 1, s + pi * i);
hang[x][i] = lie[y][i] = ge[g][i] = 0;
}
}
}
int main() {
for (int i = 1; i <= 9; ++i) {
h[i].id = i;
}
for (int i = 1; i <= 9; ++i) {
for (int j = 1; j <= 9; ++j) {
a[i][j] = read();
if (a[i][j] > 0) {
hang[i][a[i][j]] = lie[j][a[i][j]] = ge[where(i, j)][a[i][j]] = 1;
tot += a[i][j] * point(i, j);
}
else {
++h[i].sum;
}
}
}
sort(h + 1, h + 10, cmp);
for (int i = 1; i <= 9; ++i) {
for (int j = 1; j <= 9; ++j) {
if (a[h[i].id][j] == 0) {
no[++cnt][0] = h[i].id;
no[cnt][1] = j;
no[cnt][2] = where(h[i].id, j);
no[cnt][3] = point(h[i].id, j);
}
}
}
dfs(0, tot);
printf("%d\n", ans);
return 0;
}
结束
这些题难度都很大,有些是真的让人心累