洛谷P1629 邮递员送信

本文介绍了一种解决邮递员最短路径问题的方法,该问题要求计算邮递员送完所有物品并返回起点所需的最短时间。采用正向图和反向图的SPFA算法实现。

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

题目描述

有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间。这个邮递员每次只能带一样东西。求送完这N-1样东西并且最终回到邮局最少需要多少时间。

输入输出格式

输入格式:

第一行包括两个整数N和M。

第2到第M+1行,每行三个数字U、V、W,表示从A到B有一条需要W时间的道路。 满足1<=U,V<=N,1<=W<=10000,输入保证任意两点都能互相到达。

【数据规模】

对于30%的数据,有1≤N≤200;

对于100%的数据,有1≤N≤1000,1≤M≤100000。

输出格式:

输出仅一行,包含一个整数,为最少需要的时间。

输入输出样例

输入样例#1: 
5 10
2 3 5
1 5 5
3 5 6
1 2 8
1 3 8
5 3 4
4 1 8
4 5 3
3 5 6
5 4 2
输出样例#1: 
83
本来一看题,觉得是一道 TSP(货郎担)。

刚打完 状压DP ,发现数据范围巨大,再看一眼题,不就是最短路???

吃枣药丸。。。

正向图spfa+反向图spfa

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#define MAXN 1010
#define MAXM 100010
#define MAX 999999999
using namespace std;
int n,m,c=1,d=1,ans=0;
int ahead[MAXN],bhead[MAXN],apath[MAXN],bpath[MAXN];
bool vis[MAXN];
struct node{
	int next,to,w;
}a[MAXM],b[MAXM];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
void add(int u,int v,int w){
	a[c].to=v;a[c].w=w;
	a[c].next=ahead[u];
	ahead[u]=c++;
	b[d].to=u;b[d].w=w;
	b[d].next=bhead[v];
	bhead[v]=d++;
}
inline int arelax(int u,int v,int w){
	if(apath[v]>apath[u]+w){
		apath[v]=apath[u]+w;
		return 1;
	}
	return 0;
}
inline int brelax(int u,int v,int w){
	if(bpath[v]>bpath[u]+w){
		bpath[v]=bpath[u]+w;
		return 1;
	}
	return 0;
}
void aspfa(){
	int u,v;
	queue<int> q;
	for(int i=1;i<=n;i++){apath[i]=MAX;vis[i]=false;}
	apath[1]=0;
	vis[1]=true;
	q.push(1);
	while(!q.empty()){
		u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=ahead[u];i;i=a[i].next){
			v=a[i].to;
			if(arelax(u,v,a[i].w)&&!vis[v]){
				vis[v]=true;
				q.push(v);
			}
		}
	}
}
void bspfa(){
	int u,v;
	queue<int> q;
	for(int i=1;i<=n;i++){bpath[i]=MAX;vis[i]=false;}
	bpath[1]=0;
	vis[1]=true;
	q.push(1);
	while(!q.empty()){
		u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=bhead[u];i;i=b[i].next){
			v=b[i].to;
			if(brelax(u,v,b[i].w)&&!vis[v]){
				vis[v]=true;
				q.push(v);
			}
		}
	}
}
int main(){
	int u,v,w;
	n=read();m=read();
	for(int i=1;i<=m;i++){
		u=read();v=read();w=read();
		add(u,v,w);
	}
	aspfa();
	bspfa();
	for(int i=2;i<=n;i++)ans+=apath[i]+bpath[i];
	printf("%d\n",ans);
	return 0;
}
### Python 实现邮递员送信功能的模拟 要实现类似于“邮递员送信”的功能,可以将其抽象为旅行商问题 (Traveling Salesman Problem, TSP)[^1] 或者最短路径问题[^4]。这类问题是经典的组合优化问题之一,在实际应用中可以通过多种算法来求解。 #### 使用遗传算法解决 TSP 问题 一种常见的方法是采用 **遗传算法** 来寻找近似最优解。以下是基于遗传算法的一个简化版本: ```python import random import numpy as np def generate_cities(num_cities): """随机生成城市的坐标""" cities = {i: (random.uniform(0, 1), random.uniform(0, 1)) for i in range(num_cities)} return cities def calculate_distance(city_a, city_b): """计算两个城市之间的欧几里得距离""" xa, ya = city_a xb, yb = city_b return ((xa - xb)**2 + (ya - yb)**2)**0.5 def fitness_function(individual, cities): """适应度函数:总路程越短越好""" total_distance = 0 for idx in range(len(individual)): from_city_idx = individual[idx] to_city_idx = individual[(idx + 1) % len(individual)] total_distance += calculate_distance(cities[from_city_idx], cities[to_city_idx]) return 1 / total_distance def crossover(parent1, parent2): """单点交叉操作""" point = random.randint(0, len(parent1)) child = [-1] * len(parent1) # 复制父代的部分基因到子代 child[:point] = parent1[:point] # 填充剩余部分 pointer = point while any(x == -1 for x in child): if parent2[pointer] not in child: first_empty_position = child.index(-1) child[first_empty_position] = parent2[pointer] pointer = (pointer + 1) % len(parent2) return child def mutate(individual, mutation_rate=0.01): """变异操作""" for swap_i in range(len(individual)): if random.random() < mutation_rate: swap_j = int(random.random() * len(individual)) individual[swap_i], individual[swap_j] = individual[swap_j], individual[swap_i] return individual def genetic_algorithm(population_size, num_generations, num_cities, mutation_rate=0.01): """遗传算法主程序""" cities = generate_cities(num_cities) population = [list(np.random.permutation(list(range(num_cities)))) for _ in range(population_size)] best_individual = None best_fitness = float('-inf') for generation in range(num_generations): new_population = [] # 计算当前种群的适应度并选择优秀个体 fitness_scores = [(fitness_function(indiv, cities), indiv) for indiv in population] sorted_population = [indiv for _, indiv in sorted(fitness_scores, key=lambda x: x[0], reverse=True)] current_best = sorted_population[0] current_best_fitness = fitness_function(current_best, cities) if current_best_fitness > best_fitness: best_fitness = current_best_fitness best_individual = current_best # 进行繁殖过程 elite_count = max(int(0.1 * population_size), 1) # 精英策略保留前几名 new_population.extend(sorted_population[:elite_count]) while len(new_population) < population_size: parent1 = random.choice(sorted_population[:int(population_size*0.3)]) # 更倾向于选优胜个体 parent2 = random.choice(sorted_population[int(population_size*0.7):]) offspring = crossover(parent1, parent2) mutated_offspring = mutate(offspring, mutation_rate) new_population.append(mutated_offspring) population = new_population return best_individual, best_fitness, cities if __name__ == "__main__": result_path, result_fitness, generated_cities = genetic_algorithm( population_size=100, num_generations=500, num_cities=10, mutation_rate=0.01 ) print("最佳路径:", result_path) print("适应度分数(倒数总距离):", result_fitness) ``` 上述代码实现了通过遗传算法找到一条接近于全局最优的路径。其中的关键步骤包括: - 编码阶段:将每条可能的路径表示为一个排列数组。 - 解码阶段:根据该排列计算对应的路径长度作为目标函数的一部分。 - 遗传操作:包括选择、交叉和变异三个主要环节。 #### 关键概念解释 - **编码与解码**: 将问题中的可行解转化为计算机可处理的形式[^2]。 - **适应度函数**: 定义衡量解决方案质量的标准,通常是最小化或最大化某个指标。 - **遗传操作**: 包括选择更优秀的个体参与下一代繁衍以及引入一定的随机性以探索新的可能性。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值