UVA208 消防车 Firetruck

本文探讨了图的遍历及回溯算法的应用,并通过一个具体案例解释如何使用链式邻接表存储图数据结构,实现从起点到终点的所有路径查找。文章特别注意到了效率问题,介绍了如何预先判断两点间是否连通以避免不必要的遍历。

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

知识点:图的遍历,回溯

这个题其实就是图的遍历然后加上回溯,但是有点坑的是,我们在找路径之前,要先判断1是不是能到k点,否则会超时,这个要不是看提示,还真想不到,因为如果不用别的函数来判断是不是连通的话,用求解的dfs函数,是自带回溯的,如果找不到,那么会比较费时间,会把所有的路径都走一遍,总之做这种图论的题总是会有很多这种考虑不周到,最后导致错误的地方,

这里存图没用邻接矩阵,用的是董晓讲的链式邻接表,因为我们每个节点要从小到大遍历它连着的节点,所有搜索之前对每个点连着的点排序,如果是采用链式前向星的话,我想不到该怎么写程序,就没有使用那种存图方式,

还有一点需要注意的是,题目输出,一个空格就够了,不需要样例里面长度为3的空格

#include <bits/stdc++.h>

using namespace std;

const int N = 25;

int n, k, vis[N], cnt;
vector<int> h[N], chosen;
vector<pair<int, int>> e;

void add(int a, int b) {
	e.push_back(make_pair(a, b));
	h[a].push_back((int) e.size() - 1);
}

bool cmp(int a, int b) {
	return e[a].second < e[b].second;
}

bool bfs() {
	queue<int> q;
	q.push(1);
	int dist[N] = {};
	dist[1] = 1;
	while (!q.empty()) {
		int now = q.front(); q.pop();
		if (now == k) return true;
		for (int i = 0; i < (int) h[now].size(); i++) {
			int ind = h[now][i];
			int y = e[ind].second;
			if (dist[y]) continue;
			q.push(y);
			dist[y] = 1;
		}
	}
	return false;
}

void dfs(int x) {
	if (x == k) {
		for (int i = 0; i < (int) chosen.size(); i++) {
			cout << chosen[i] << (i < (int) chosen.size() - 1 ? " " : "\n");
		}
		cnt++;
		return;
	}
	for (int i = 0; i < (int) h[x].size(); i++) {
		int ind = h[x][i];
		int y = e[ind].second;
		if (vis[y]) continue;
		vis[y] = 1;
		chosen.push_back(y);
		dfs(y);
		chosen.pop_back();
		vis[y] = 0;
	}
}

int main() {
	int tt = 1;
	while (cin >> k) {
		n = 0; cnt = 0;
		e.clear();
		for (int i = 0; i < N; i++) h[i].clear();
		cout << "CASE " << tt++ << ":\n";
		int a, b;
		while (cin >> a >> b && a) {
			add(a, b);
			add(b, a);
			n = max(n, max(a, b));
		}
		for (int i = 1; i <= n; i++) {
			sort(h[i].begin(), h[i].end(), cmp);
		}
		if (bfs()) {
			vis[1] = 1;
			chosen.push_back(1);
			dfs(1);
			vis[1] = 0;
			chosen.pop_back();
		}
		printf("There are %d routes from the firestation to streetcorner %d.\n", cnt, k);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值