迭代加深-双向DFS-IDAstar

简介: 笔记

迭代加深


避免搜索过深 但答案在较浅的位置这种情况的发生


AcWing170. 加成序列

满足如下条件的序列X(序列中元素被标号为1、2、3…m)被称为“加成序列”:

30.png

你的任务是:给定一个整数n,找出符合上述条件的长度m最小的“加成序列”。


如果有多个满足要求的答案,只需要找出任意一个可行解。


输入格式

输入包含多组测试用例。


每组测试用例占据一行,包含一个整数n。


当输入为单行的0时,表示输入结束。


输出格式

对于每个测试用例,输出一个满足需求的整数序列,数字之间用空格隔开。


每个输出占一行。


数据范围

1 ≤ n ≤ 100


剪枝策略

优化搜索顺序:① 优先枚举较大的数


排除等效冗余:① 某两对数和相等时 只需要选择其中一对


代码

#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int n;
int ans[N];
bool dfs(int u, int depth) {
  if (u > depth)return false;
  if (ans[u - 1] == n)return true;
  bool st[N] = { 0 };
  for (int i = u - 1; i >= 0; --i) {
    for (int j = i; j >= 0; --j) {
      int s = ans[i] + ans[j];
      if (st[s] || s > n || s <= ans[u - 1])continue;
      st[s] = true;
      ans[u] = s;
      if (dfs(u + 1, depth))return true;
    }
  }
  return false;
}
int main() {
  ans[0] = 1;
  while (cin >> n, n) {
    int depth = 1;
    while (!dfs(1, depth))depth++;
    for (int i = 0; i < depth; ++i)printf("%d ", ans[i]);
    cout << endl;
  }
}


双向DFS


AcWing171. 送礼物

达达帮翰翰给女生送礼物,翰翰一共准备了N个礼物,其中第i 个礼物的重量是G [ i]


达达的力气很大,他一次可以搬动重量之和不超过W的任意多个物品。


达达希望一次搬掉尽量重的一些物品,请你告诉达达在他的力气范围内一次性能搬动的最大重量是多少。


输入格式

第一行两个整数,分别代表W和N。


以后N行,每行一个正整数表示G[i]。


输出格式

仅一个整数,表示达达在他的力气范围内一次性能搬动的最大重量。


数据范围

31.png

剪枝策略

1.将所有物品按重量从大到小排序


2.先将前k 件物品能凑出的重量打表,然后排序判重


3.搜索剩下的N − K 件物品的选择方式 并从表中二分出不超过W的最大值


代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 50;
int n, m;
int w[N], weights[1 << 25];
int k, cnt = 1, res;
void dfs1(int u, int s) {
  if (u == k) {
    weights[cnt++] = s;
    return;
  }
  dfs1(u + 1, s);
  if ((LL)s + w[u] <= m)dfs1(u + 1, s + w[u]);
}
void dfs2(int u, int s) {
  if (u == n) {
    int l = 0, r = n;
    while (l < r) {
      int mid = l + r + 1 >> 1;
      if (weights[mid] <= m - s)l = mid;
      else r = mid - 1;
    }
    res = max(res, weights[l] + s);
    return;
  }
  dfs2(u + 1, s);
  if ((LL)s + w[u] <= m)dfs2(u + 1, s + w[u]);
}
int main() {
  cin >> m >> n;
  for(int i = 1;i <= n;++i){
    scanf("%d", &w[i]);
  }
  sort(w, w + n);
  reverse(w, w + n);
  int k = n / 2 + 2;
  dfs1(1, 0);
  cnt = unique(weights, weights + cnt) - weights;
  dfs2(k + 1, 0);
  cout << res << endl;
  return 0;
}

IDA-star


启发式搜索 + 迭代加深


如果估价函数(需要再搜的最小层数) + 当前层数 > 当前迭代加深的层数 在当前迭代肯定无解


迭代扩大搜索的层数 直到最终找到答案 或者无解


AcWing180. 排书

给定n本书,编号为1-n。


在初始状态下,书是任意排列的。


在每一次操作中,可以抽取其中连续的一段,再把这段插入到其他某个位置。


我们的目标状态是把书按照1-n的顺序依次排列。


求最少需要多少次操作。


输入格式

第一行包含整数T ,表示共有T 组测试数据。


每组数据包含两行,第一行为整数n,表示书的数量。


第二行为n nn个整数,表示1 − n 的一种任意排列。


同行数之间用空格隔开。


输出格式

每组数据输出一个最少操作次数。


如果最少操作次数大于或等于5次,则输出”5 or more”。


每个结果占一行。


数据范围

1 ≤ n ≤ 15


思路

枚举移动串的长度 和插入的位置 一层一层地搜


代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 15;
int n;
int a[N], w[5][N];
int f() {
  int cnt = 0;
  for (int i = 0; i + 1 < n; ++i)
    if (a[i + 1] != a[i] + 1)
      ++cnt;
  return (cnt + 2) / 3;
}
bool dfs(int depth, int max_depth) {
  if (depth + f() > max_depth)return false; 
  if (f() == 0)return true;
  for (int len = 1; len <= n; ++len) {  //枚举当前移动的长度
    for (int l = 0; l + len - 1 < n; ++l) { //枚举截取的起点
      int r = l + len - 1; //计算终点
      // 把 l 到 r 这一段放到k的后面去
      for (int k = r + 1; k < n; ++k) {// 枚举应该插在哪个地方 避免重复 每次都往后放
        memcpy(w[depth], a, sizeof a);
        int y = l;
        for (int x = r + 1; x <= k; ++x,++y)a[y] = w[depth][x];
        for (int x = l; x <= r; ++x, ++y)a[y] = w[depth][x];
        if (dfs(depth + 1, max_depth))return true;
        memcpy(a, w[depth], sizeof a);
      }
    }
  }
  return false;
}
int main() {
  int t; cin >> t;
  while (t--) {
    cin >> n;
    for (int i = 0; i < n; ++i)scanf("%d", &a[i]);
    int depth = 0;
    while (depth < 5 && !dfs(0, depth))depth++;
    if (depth >= 5)puts("5 or more");
    else cout << depth << endl;
  }
}


AcWing181. 回转游戏

如下图所示,有一个“#”形的棋盘,上面有1,2,3三种数字各8个。


给定8种操作,分别为图中的A~H。


这些操作会按照图中字母和箭头所指明的方向,把一条长为8的序列循环移动1个单位。


例如下图最左边的“#”形棋盘执行操作A后,会变为下图中间的“#”形棋盘,再执行操作C后会变成下图最右边的“#”形棋盘。


给定一个初始状态,请使用最少的操作次数,使“#”形棋盘最中间的8个格子里的数字相同。

输入格式

输入包含多组测试用例。


每个测试用例占一行,包含24个数字,表示将初始棋盘中的每一个位置的数字,按整体从上到下,同行从左到右的顺序依次列出。


输入样例中的第一个测试用例,对应上图最左边棋盘的初始状态。


当输入只包含一个“0”的行时,表示输入终止。


输出格式

每个测试用例输出占两行。


第一行包含所有移动步骤,每步移动用大写字母“A~G”中的一个表示,字母之间没有空格,如果不需要移动则输出“No moves needed”。


第二行包含一个整数,表示移动完成后,中间8个格子里的数字。


如果有多种方案,则输出字典序最小的解决方案。


代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 24;
int op[8][7] = { //图表顺序
  {0,2,6,11,15,20,22},
  {1,3,8,12,17,21,23},
  {10,9,8,7,6,5,4},
  {19,18,17,16,15,14,13},
  {23,21,17,12,8,3,1},
  {22,20,15,11,6,2,0},
  {13,14,15,16,17,18,19},
  {4,5,6,7,8,9,10},
};
int opposite[8] = { 5,4,7,6,1,0,3,2 }; //每个操作对应的逆操作
int center[8] = { 6,7,8,11,12,15,16,17 };
int q[N];
int path[100];
int f() {
  int sum[4] = { 0 };
  for (int i = 0; i < 8; ++i) {
    sum[q[center[i]]]++;
  }
  int s = 0;
  for (int i = 1; i <= 3; ++i) {
    s = max(s, sum[i]);
  }
  return 8 - s;
}
void operate(int x) {
  int s = q[op[x][0]];
  for (int i = 0; i < 6; ++i) {
    q[op[x][i]] = q[op[x][i + 1]];
  }
  q[op[x][6]] = s;
}
bool dfs(int depth, int max_depth,int last) {
  if (depth + f() > max_depth)return false;
  if (!f())return true;
  for (int i = 0; i < 8; ++i) {
    if (opposite[i] != last) {
      operate(i);
      path[depth] = i;
      if (dfs(depth + 1, max_depth,i))return true;
      operate(opposite[i]);
    }
  }
  return false;
}
int main() {
  while (cin >> q[0], q[0]) {
    for (int i = 1; i < 24; ++i)scanf("%d", &q[i]);
    int depth = 0;
    while (!dfs(0, depth,-1))depth++;
    if (!depth)printf("No moves needed");
    else {
      for (int i = 0; i < depth; ++i)printf("%c", path[i] + 'A');
    }
    printf("\n%d\n", q[6]);
  }
}



目录
相关文章
|
2月前
|
算法
DFS算法的实现
DFS算法的实现
39 3
|
4月前
|
算法 索引
DFS算法及应用(二)
回溯:回溯就是DFS的一种,在搜索探索过程中寻找问题的解,当发现不满足求解条件时,就回溯返回,尝试其他路径。
|
4月前
|
算法
DFS算法及应用(一)
DFS(深度优先搜索)是一种图遍历算法,常用于解决穷举问题,如全排列、迷宫问题、图的连通性等。它沿着树的深度分支进行探索,直至达到叶子节点,若无法继续则回溯。例如,将数字6拆分为3个正整数的递增序列问题可以通过DFS实现,类似地,分糖果问题和买瓜问题同样可以用DFS求解。DFS通常涉及递归或栈结构,通过标记已访问节点避免重复。在编程中,会定义递归函数,设定结束条件,然后枚举可能的情况,并处理下一层节点。
|
5月前
|
算法 C++
c++算法学习笔记 (6) DFS
c++算法学习笔记 (6) DFS
|
5月前
|
算法
深度优先搜索(DFS)的基础理解与实现
深度优先搜索(DFS)的基础理解与实现
60 0
|
11月前
迭代加深+双向dfs+IDA*
迭代加深+双向dfs+IDA*
57 0
|
11月前
|
算法
算法学习--DFS
算法学习--DFS
|
算法 前端开发
怎么理解DFS和BFS
怎么理解DFS和BFS
159 0