在不同的问题中,搜索树的各个层次、各个分支之间的顺序不是固定的,不同的搜索顺序会产生不同的搜索树形态,其规模大小也相差甚远。
在搜索过程中,若能判断从搜索树当前节点上沿某几条不同分支到达的子树是相同的,那么只需对其中一条分支执行搜索。
可行性剪枝也叫上下界剪枝,其是指在搜索过程中,及时对当前状态进行检查,若发现分支已无法到达递归边界,就执行回溯。
在最优化问题的搜索过程中,若当前花费的代价已超过当前搜索到的最优解,那么无论采取多么优秀的策略到达递归边界,都不可能更新答案,此时可以停止对当前分支的搜索进行回溯。
p s ps ps:懒得放题解了,凑合看吧,zzz
题目链接
题意:将整数 n n n分成 k k k份,且每份不能为空,问有多少种不同的分法
直接搜会 T T T,要想剪枝:
借大佬说的话:
因为保证没有重复方案,就必须保证枚举的结果递增(或者递减)。假设当前选择的数为 x x x,那么后面所有的数必须 ≥ x ≥x ≥x,如果此时让剩下的数都 = x =x =x,还比 n n n小,那么剩下的几次递归其实都是无用的,这就是这一题的可行性剪枝。
#include
#include
#include
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
int n, k, ans;
void dfs(int last, int cnt, int sum) {
if(sum > n) return;
if(cnt == k) {
if(sum == n) ans++;
return;
}
for(int i = last; sum + i * (k - cnt) <= n; i++) {
dfs(i, cnt + 1, sum + i);
}
}
int main() {
n = read(), k = read();
dfs(1, 0, 0);
cout << ans << '\n';
return 0;
}
题目链接
#include
#include
#include
#include
#include
using namespace std;
const int A = 30;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m;
int minv[A], mins[A], ans = inf, h[A], r[A], s = 0, v = 0;
void dfs(int dep) {
if(!dep) {
if(v == n) ans = min(ans, s);
return;
}
for(r[dep] = min((int)sqrt(n - v), r[dep + 1] - 1); r[dep] >= dep; r[dep]--)
for(h[dep] = min((int)((double)(n-v) / r[dep] / r[dep]), h[dep + 1] - 1); h[dep] >= dep; h[dep]--) {
if (v + minv[dep - 1] > n) continue;
if (s + mins[dep - 1] > ans) continue;
if (s + (double)2 * (n - v) / r[dep] > ans) continue;
if(dep == m) s += r[dep] * r[dep];
s += 2 * r[dep] * h[dep];
v += r[dep] * r[dep] * h[dep];
dfs(dep - 1);
if (dep == m) s -= r[dep] * r[dep];
s -= 2 * r[dep] * h[dep];
v -= r[dep] * r[dep] * h[dep];
}
}
int main() {
n = read(), m = read();
minv[0] = mins[0] = 0;
for(int i = 1; i <= m; i++) {
minv[i] = minv[i - 1] + i * i * i;
mins[i] = mins[i - 1] + i * i;
}
h[m + 1] = r[m + 1] = inf;
dfs(m);
cout << ans << "\n";
return 0;
}
题目链接
#include
#include
#include
#include
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 101;
int n, a[N], sum, len, maxn, vis[N], cnt, ll, tot;
bool dfs(int now, int lo, int last) {
if(now == tot + 1 && lo == len) return true;
if(lo == len) lo = 0, last = 0;
for(int i = last + 1; i <= tot; i++) {
if(vis[i]) continue;
if(a[i] + lo > len) continue;
vis[i] = 1;
if(dfs(now + 1, lo + a[i], i)) return true;
vis[i] = 0;
if(lo == 0 || lo + a[i] == len) return false;
while(a[i] == a[i + 1]) i++;
}
return false;
}
bool cmp(int a, int b) {
return a > b;
}
int main() {
n = read();
sum = 0, maxn = 0;
for(int i = 1; i <= n; i++) {
int x = read();
if(x <= 50) {
a[++tot] = x;
maxn = max(maxn, a[tot]);
sum += a[tot];
}
}
stable_sort(a + 1, a + 1 + tot, cmp);
// cout << sum << '\n';
// for(int i = 1; i <= tot; i++) cout << a[i] << ' ';
for(len = maxn; len <= sum; len++) {
if(sum % len) continue;
if(dfs(1, 0, 0)) {
cout << len;
return 0;
}
}
cout << sum << '\n';
return 0;
}
题目链接
#include
#include
#include
#include
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int a[A], ans[A], minn, n;
void dfs(int now) {
if(now > minn || a[now] > n) return;
if(a[now] == n) {
if(now > minn) return;
minn = now;
for(int i = 1; i <= now; i++) ans[i] = a[i];
return;
}
for(int i = now; i >= 1; i--) {
if(a[now] + a[i] > n) continue;
a[now + 1] = a[now] + a[i];
dfs(now + 1);
a[now + 1] = 0;
}
return;
}
int main() {
while(scanf("%d", &n) != EOF) {
if(n == 0) break;
minn = inf, a[1] = 1;
dfs(1);
for(int i = 1; i <= minn; i++) cout << ans[i] << " ";
puts("");
}
return 0;
}
题目链接
神奇的搜索对象
#include
#include
#include
#include
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int x, n, m, p, sum[A], a[A];
bool vis[A];
bool dfs(int cnt, int l, int r, int lsum, int rsum) {
if(l == r) {
if(!vis[sum[cnt] - lsum] && !vis[sum[cnt] - rsum]) return 0;
a[l] = sum[n * 2] - lsum - rsum;
if(a[l] < 1 || a[l] > 500) return 0;
for(int i = 1; i <= cnt; i++) cout << a[i] << " ";
return 1;
}
if(vis[sum[cnt] - lsum]) {
a[l] = sum[cnt] - lsum;
if(dfs(cnt + 1, l + 1, r, sum[cnt], rsum)) return 1;
}
if(vis[sum[cnt] - rsum]) {
a[r] = sum[cnt] - rsum;
if(dfs(cnt + 1, l, r - 1, lsum, sum[cnt])) return 1;
}
return 0;
}
int main() {
n = read();
for(int i = 1; i <= 2 * n; i++) sum[i] = read();
m = read();
for(int i = 1; i <= m; i++) x = read(), vis[x] = 1;
stable_sort(sum + 1, sum + 1 + n * 2);
dfs(1, 1, n, 0, 0);
}
题目链接
#include
#include
#include
#include
#define int long long
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, cur[1005], ans[1005], mn;
void dfs(int x, int a, int b, int n, int last) {
if (x == n) {
if(b % a) return;
b /= a; cur[x] = b;
if(b < mn) {
mn = b;
for(int i = 1; i <= n; i++) ans[i] = cur[i];
}
return;
}
last++;
while(a * last <= b && last < mn) last++;
for(; last < mn; last++) {
if(a * last >= b * (n - x + 1)) break;
cur[x] = last;
dfs(x + 1, a * last - b, b * last, n, last);
}
return;
}
signed main() {
n = read(), m = read();
int i = 1; mn = 1e9;
while(1) {
dfs(1, n, m, i, 0);
if(mn < 1e9) break;
i++;
}
for(int j = 1; j <= i; j++) cout << ans[j] << " ";
return 0;
}
题目链接
#include
#include
#include
#include
#include
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n;
vector <int> on[20];
struct node { int x1, y1, x2, y2, col; } a[A];
int ans = inf, vis[A];
bool check(int k) {
int siz = (int)on[k].size();
for(int i = 0; i < siz; i++) if(!vis[on[k][i]]) return 0;
return 1;
}
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] && check(i)) {
vis[i] = 1;
dfs(tot + (col != a[i].col), fin + 1, a[i].col);
vis[i] = 0;
}
}
}
int main() {
n = read();
for(int i = 1; i <= n; i++)
a[i].x1 = read(), a[i].y1 = read(), a[i].x2 = read(), a[i].y2 = read(), a[i].col = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i != j && a[i].x1 == a[j].x2 && a[i].y2 >= a[j].y1 && a[i].y1 <= a[j].y2)
on[i].push_back(j);
// for(int i = 1; i <= n; i++) {
// int t = on[i].size(); cout << "size: " << t << "\n";
// for(int j = 0; j < t; j++) cout << on[i][j] <<" "; puts("");
// }
dfs(0, 0, 0);
cout << ans << '\n'; return 0;
}
题目链接
特别想说一下这道题,因为真的特!别!好!玩!
数独都懂吧
1. 1. 1.每一行不能有一样的数字
2. 2. 2.每一列不能有一样的数字
3. 3. 3.每个 3 ∗ 3 3*3 3∗3的九宫格不能有一样的数字
首先上来的感觉就是要搜索,那么,搜索的话,我们要想一下怎么搜,这里可以直接记录某一行某个数是否出现,某一列某个数是否出现,某个九宫格内某个数是否出现,前两个好弄,直接循环的时候记录就好了,最后一个怎么办?
而且怎么计算格子的分数呢??一个一个乘?
所以,我们要解决的问题是:怎么计算格子的分数,怎么判断是第几个九宫格
const int score[10][10] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 6, 6, 6, 6, 6, 6, 6, 6, 6},
{0, 6, 7, 7, 7, 7, 7, 7, 7, 6},
{0, 6, 7, 8, 8, 8, 8, 8, 7, 6},
{0, 6, 7, 8, 9, 9, 9, 8, 7, 6},
{0, 6, 7, 8, 9,10, 9, 8, 7, 6},
{0, 6, 7, 8, 9, 9, 9, 8, 7, 6},
{0, 6, 7, 8, 8, 8, 8, 8, 7, 6},
{0, 6, 7, 7, 7, 7, 7, 7, 7, 6},
{0, 6, 6, 6, 6, 6, 6, 6, 6, 6}, };
int pd(int i, int j) {
if(i <= 3 && j <= 3) return 1;
if(i <= 3 && j <= 6) return 2;
if(i <= 3 && j <= 9) return 3;
if(i <= 6 && j <= 3) return 4;
if(i <= 6 && j <= 6) return 5;
if(i <= 6 && j <= 9) return 6;
if(i <= 9 && j <= 3) return 7;
if(i <= 9 && j <= 6) return 8;
if(i <= 9 && j <= 9) return 9;
}
然后我们就可以一行一行的搜索,填完一行再填下一行,然后就可以得到六十分的好成绩
#include
#include
#include
#include
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
const int score[10][10] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 6, 6, 6, 6, 6, 6, 6, 6, 6},
{0, 6, 7, 7, 7, 7, 7, 7, 7, 6},
{0, 6, 7, 8, 8, 8, 8, 8, 7, 6},
{0, 6, 7, 8, 9, 9, 9, 8, 7, 6},
{0, 6, 7, 8, 9,10, 9, 8, 7, 6},
{0, 6, 7, 8, 9, 9, 9, 8, 7, 6},
{0, 6, 7, 8, 8, 8, 8, 8, 7, 6},
{0, 6, 7, 7, 7, 7, 7, 7, 7, 6},
{0, 6, 6, 6, 6, 6, 6, 6, 6, 6}, };
int pd(int i, int j) {
if(i <= 3 && j <= 3) return 1;
if(i <= 3 && j <= 6) return 2;
if(i <= 3 && j <= 9) return 3;
if(i <= 6 && j <= 3) return 4;
if(i <= 6 && j <= 6) return 5;
if(i <= 6 && j <= 9) return 6;
if(i <= 9 && j <= 3) return 7;
if(i <= 9 && j <= 6) return 8;
if(i <= 9 && j <= 9) return 9;
}
int a[11][11], hang[11][11], lie[11][11], sma[11][11];
int tot, ans = -10000;
void coun() {
int now = 0;
for(int i = 1; i <= 9; i++)
for(int j = 1; j <= 9; j++)
now += a[i][j] * score[i][j];
ans = max(ans, now);
return;
}
void dfs(int ho, int li) { //行、列、这一行填了多少个
if(ho == 10) { coun(); return; }
if(li == 10) dfs(ho + 1, 1);
if(!a[ho][li]) {
for(int i = 1; i <= 9; i++) {
if(!hang[ho][i] && !lie[li][i] && !sma[pd(ho, li)][i]) {
hang[ho][i] = lie[li][i] = sma[pd(ho, li)][i] = 1;
a[ho][li] = i; dfs(ho, li + 1); a[ho][li] = 0;
hang[ho][i] = lie[li][i] = sma[pd(ho, li)][i] = 0;
}
}
}
else dfs(ho, li + 1);
}
int main() {
for(int i = 1; i <= 9; i++)
for(int j = 1; j <= 9; j++) {
a[i][j] = read();
if(a[i][j]) {
sma[pd(i, j)][a[i][j]] = 1;
hang[i][a[i][j]] = 1;
lie[j][a[i][j]] = 1;
}
else tot++;
}
dfs(1, 1);
cout << ans << "\n";
return 0;
}
怎么优化?
我不会优化呀!!怎么办!只能搜了……只见大佬说
从填数最多的一行开始填,这样要选择的数就少了,不合法的情况就可以省掉一些
然后就满分了 q w q qwq qwq
#include
#include
#include
#include
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
const int score[10][10] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 6, 6, 6, 6, 6, 6, 6, 6, 6},
{0, 6, 7, 7, 7, 7, 7, 7, 7, 6},
{0, 6, 7, 8, 8, 8, 8, 8, 7, 6},
{0, 6, 7, 8, 9, 9, 9, 8, 7, 6},
{0, 6, 7, 8, 9,10, 9, 8, 7, 6},
{0, 6, 7, 8, 9, 9, 9, 8, 7, 6},
{0, 6, 7, 8, 8, 8, 8, 8, 7, 6},
{0, 6, 7, 7, 7, 7, 7, 7, 7, 6},
{0, 6, 6, 6, 6, 6, 6, 6, 6, 6}, };
int pd(int i, int j) {
if(i <= 3 && j <= 3) return 1;
if(i <= 3 && j <= 6) return 2;
if(i <= 3 && j <= 9) return 3;
if(i <= 6 && j <= 3) return 4;
if(i <= 6 && j <= 6) return 5;
if(i <= 6 && j <= 9) return 6;
if(i <= 9 && j <= 3) return 7;
if(i <= 9 && j <= 6) return 8;
if(i <= 9 && j <= 9) return 9;
}
int a[11][11], hang[11][11], lie[11][11], sma[11][11];
int tot, ans = -1;
struct node { int sum, line; } qwq[11];
bool cmp(node a, node b) {
return a.sum < b.sum;
}
void coun() {
int now = 0;
for(int i = 1; i <= 9; i++)
for(int j = 1; j <= 9; j++)
now += a[i][j] * score[i][j];
ans = max(ans, now);
return;
}
void dfs(int cnt, int ho, int li) { //行、列、这一行填了多少个
if(cnt == 10) { coun(); return; }
if(li == 10) dfs(cnt + 1, qwq[cnt + 1].line, 1);
if(!a[ho][li]) {
for(int i = 1; i <= 9; i++) {
if(!hang[ho][i] && !lie[li][i] && !sma[pd(ho, li)][i]) {
hang[ho][i] = lie[li][i] = sma[pd(ho, li)][i] = 1;
a[ho][li] = i; dfs(cnt, ho, li + 1); a[ho][li] = 0;
hang[ho][i] = lie[li][i] = sma[pd(ho, li)][i] = 0;
}
}
}
else dfs(cnt, ho, li + 1);
}
int main() {
for(int i = 1; i <= 9; i++) {
tot = 0;
for(int j = 1; j <= 9; j++) {
a[i][j] = read();
if(a[i][j]) {
sma[pd(i, j)][a[i][j]] = 1;
hang[i][a[i][j]] = 1;
lie[j][a[i][j]] = 1;
}
else tot++;
qwq[i].line = i, qwq[i].sum = tot;
}
}
sort(qwq + 1, qwq + 1 + 9, cmp);
dfs(1, qwq[1].line, 1);
cout << ans; return 0;
}