迭代加深搜索 整理 Addition Chains、UVA1283 Infiltration

本文深入解析迭代加深搜索算法,探讨其在解决特定问题中的应用,如构造最短数列和控制细胞网络。文章通过实例说明如何结合深度优先搜索与广度优先搜索的优势,实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

迭代加深搜索

DFS 最大的缺陷在于每个搜索分支深入过深
当答案在比较浅的位置的时候花费了过多的时间在无效搜索分支中

迭代加深搜索首先深度优先搜索 k 层
若没有找到可行解,再深度优先搜索 k+1 层,直到找到可行解为止

由于深度是从小到大逐渐增大的,所以当搜索到结果时可以保证搜索深度是最小的

本质:迭代加深本质上是通过枚举的手段为 DFS 增加了一个深度条件剪枝

Addition Chains

题意

给出一个数 n n n,你现在有一个 1 1 1
你可以将已有的数字相加得到一个新的数字,直到得到 n n n
输出你用的数列,要求长度最短

分析

迭代深搜
第一想法是bfs,搜索至少几个数字构成数列
但是构造数列需要dfs实现
也就是说这是一个bfs+dfs=迭代深搜
枚举数组长度,dfs
剪枝

  • 至少p位数列 ( 2 p > = n ) (2^p>=n) (2p>=n)
  • 显然构造一个递增数列,产生的新数必须更大
  • 因为每次最多乘2倍,所以我们可以预判最大的数,是否能超过n

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
int n, a[233], k;
bool flag = false;
void dfs(int x) {
	if (flag) return;
	if (x == k + 1) {
		if (a[x - 1] == n)
			flag = true;
		return;
	}
	for (int i = 1; i < x; i++) {
		for (int j = i; j < x; j++) {
			if (a[i] + a[j] > a[x - 1] && a[i] + a[j] <= n && 
				(LL(a[i] + a[j]) << (k - x)) >= n) {
				a[x] = a[i] + a[j];
				dfs(x + 1);
				if (flag)return;
			}
		}
	}
}
int main() {
	while (~scanf("%d", &n) && n) {
		if (n == 1) {
			printf("1\n");
			continue;
		}
		memset(a, 0, sizeof(a));
		int p = n; a[1] = 1; k = 0;		
		while (p) {
			p >>= 1;
			k++;
		}
		for (int i = 1; i <= n; i++) {
			flag = false;
			dfs(2);
			if (flag) {
				for (int j = 1; j < k; j++)
					printf("%d ", a[j]);
				printf("%d\n", a[k]);
				break;
			}
			k++;
		}
	}
}

UVA1283 Infiltration

题意

有一些细胞可以控制另一些细胞,若你控制了一些细胞,那么就 控制了它直接控制的细胞,问需要控制多少细胞才可以控制所有 的细胞,每两个细胞之间都有控制和被控制的关系

  • 给出 n(n≤ 75) 个细胞
  • 有一些细胞可以控制另一些细胞,若你控制了一些细胞,那么就控制了它直接控制的细胞
  • 每两个细胞之间都有控制和被 控制的关系

问需要控制多少细胞才可以控制所有的细胞

分析

一开始感觉点的数量很多,没什么想法

但是我们注意到所有细胞之间都有控制和被控制的关系

那么这就是一个完全图(竞赛图)

而竞赛图拥有一些优美的性质

  • 如果有环,必然存在三元环
  • 一定存在哈密顿路径
  • 存在哈密顿回路的充要条件是强联通
  • 最小点支配集大小不超过 log(n)

我们注意到最小点支配集不超过logn

支配集:令一个图为V-E,V为点集,E为边集,
支配集S为V的一个子集,使得S中任意一个点的连线和V-S中任意一个点的连线均属于边集E

所以,本题所需最多的点为logn

然后我们考虑搜索即可

最小点数需要bfs

输出由哪些点控制需要dfs

dfs+bfs=迭代加深搜索

枚举深度为1-logn

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <bitset>
using namespace std;
#pragma warning (disable:4996)
typedef bitset<100> Bit;
const int maxn = 105;
int n, deep; bool flag;
int ans[maxn];
char s[maxn][maxn];
Bit b[maxn];
void init() {
	for (int i = 1; i <= n; i++) {
		b[i].reset(); b[i][i] = 1;
		for (int j = 1; j <= n; j++)
			if (s[i][j] == '1')
				b[i][j] = 1;
	}
	deep = 1; flag = false; 
	memset(ans, 0, sizeof(ans));
}
void dfs(int x, int step, Bit k) {
	if (step == deep + 1) {
		if (k.count() == n) flag = true;
		return;
	}
	for (int i = x; i <= n; i++) {
		ans[step] = i;
		dfs(i + 1, step + 1, k | b[i]);
		if (flag)return;
	}
}
int main() {
	int g = 0;
	while (~scanf("%d", &n)) {
		for (int i = 1; i <= n; i++)
			scanf("%s", s[i] + 1);
		init();
		for (int i = 1; i <= n; i++, deep++) {//logn时候肯定能截止
			dfs(1, 1, Bit(0));
			if (flag)break;
		}
		printf("Case %d: %d",++g, deep);
		for (int i = 1; i <= deep; i++)
			printf(" %d", ans[i]);
		printf("\n");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值