2.6学习总结

2.6
1.蓝桥公园
2.路径
3.打印路径
4.【模板】Floyd

Floyd算法:

是一种多源的最短路径算法,经过一次计算可以得到任意两个点之间的最短路径。

这种算法是基于动态规划的思想:

m[i][j]表示从i到j这条边的距离,dp[k][i][j]表示从i到j且经过{0,1,...,k-1}中若干点的最短路径。

那么转移方程就就是dp[k][i][j]=min(dp[k−1][i][j],dp[k−1][i][k]+dp[k−1][k][j])这表示了比较经过k和不经过k两种的情况的路径,找到较小值

例如,在k=1的时候,
d p [ 1 ] [ i ] [ j ] = m i n ( d p [ 0 ] [ i ] [ j ] , d p [ 0 ] [ i ] [ 1 ] + d p [ 0 ] [ 1 ] [ j ] ) = m i n ( m [ i ] [ j ] , m [ i ] [ 1 ] + m [ 1 ] [ j ] )         
2.6学习总结_第1张图片

通过滚动数组,我们可以优化dp数组的空间,将他从三维的数组变成二维的

dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])

与其他最短路径相比Floyd算法有以下几点特点:

1.可以找到所有节点之间的最短距离

2.代码简单,就三重循环

3.效率比较低,是O(n^3)的时间复杂度

这是算法的模版:

void floyd(){
	for (int k=1;k<=n;++k){
		for (int i=1;i<=n;++i){
			for (int j=1;j<=n;++j){
				if(i!=j)dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
				else dp[i][j]=dp[j][i]=0;
			}
		}
	}
}

蓝桥公园:https://www.lanqiao.cn/problems/1121/learning/?page=1&first_category_id=1&status=2

#include 
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
const int INF=0x3f3f3f3f3f3f3f3fll; 
const int N=405;
int dp[N][N];
int n,m,q;
void input(){
	memset(dp,0x3f,sizeof(dp));
	for (int i=1;i<=m;++i){
		int u,v,w;
		cin>>u>>v>>w;
		dp[u][v]=dp[v][u]=min(dp[u][v],w);
	}
}
void fioyd(){
	for (int k=1;k<=n;++k){
		for (int i=1;i<=n;++i){
			for (int j=1;j<=n;++j){
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
			}
		}
	}
}
void output(){
	while (q--){
		 int s,t; cin>>s>>t;
		if (s==t) cout<<0<>n>>m>>q;
	input(); fioyd();  output();
	return 0;
}

路径:https://www.lanqiao.cn/problems/1460/learning/?page=1&first_category_id=1&problem_id=1460

#include 
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
const int INF=0x3f3f3f3f;
const int N=2050;
int dp[N][N];
int gcd(int a,int b){
	if (b==0) return a;
	return gcd(b,a%b);
}
void floyd(){
	for (int k=1;k<=2021;++k){
		for (int i=1;i<=2021;++i){
			for (int j=1;j<=2021;++j){
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
			}
		}
	}
}
signed main(){
	for (int i=1;i<2021;++i){
		for (int j=i+1;j<=2021;++j){
			if (abs(i-j)>21){
				dp[i][j]=dp[j][i]=INF;
			}else if (abs(i-j)<=21){
				dp[i][j]=dp[j][i]=(i*j)/gcd(i,j);
			}
		}
	}
	floyd();
	cout<
打印路径:https://www.lanqiao.cn/problems/1656/learning/?page=1&first_category_id=1&problem_id=1656

这道题需要的点比较多,需要记录最短路径,还有每个 城市都会收税,记录最短路径的话,就再建一个二维数组,记录每个点之间的关系

#include 
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
const int INF=0x3f3f3f3f;
const int N=505;
int n;
int dp[N][N],shui[N],path[N][N];
void input(){
	cin>>n;
	for (int i=1;i<=n;++i){
		for (int j=1;j<=n;++j){
			int x;	cin>>x;
			if (x==-1) dp[i][j]=dp[j][i]=INF;
			else{
				dp[i][j]=dp[j][i]=x;
			}
			path[i][j]=j;
		}
	}
	for (int i=1;i<=n;++i) cin>>shui[i];
}
void floyd(){
	for (int k=1;k<=n;++k){
		for (int i=1;i<=n;++i){
			for (int j=1;j<=n;++j){
				if (dp[i][j]>dp[i][k]+dp[k][j]+shui[k]){
					dp[i][j]=dp[i][k]+dp[k][j]+shui[k];
					path[i][j]=path[i][k];
				}else if (dp[i][k]+dp[k][j]+shui[k]==dp[i][j] && path[i][k]>s>>t){
		if (s==-1 && t==-1)break;
		cout<<"From "<"<

【模板】Floydhttps://www.luogu.com.cn/problem/B3647

题目描述

给出一张由 �n 个点 �m 条边组成的无向图。

求出所有点对 (�,�)(i,j) 之间的最短路径。

输入格式

第一行为两个整数 �,�n,m,分别代表点的个数和边的条数。

接下来 �m 行,每行三个整数 �,�,�u,v,w,代表 �,�u,v 之间存在一条边权为 �w 的边。

输出格式

输出 �n 行每行 �n 个整数。

第 �i 行的第 �j 个整数代表从 �i 到 �j 的最短路径。

输入输出样例

输入 #1复制

4 4
1 2 1
2 3 1
3 4 1
4 1 1

输出 #1复制

0 1 2 1
1 0 1 2
2 1 0 1
1 2 1 0

说明/提示

对于 100%100% 的数据,�≤100n≤100,�≤4500m≤4500,任意一条边的权值 �w 是正整数且 1⩽�⩽10001⩽w⩽1000。

数据中可能存在重边。

#include 
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
const int INF=0x3f3f3f3f;
const int N=505;
int n,m;
int dp[N][N];
void floyd(){
	for (int k=1;k<=n;++k){
		for (int i=1;i<=n;++i){
			for (int j=1;j<=n;++j){
				if(i!=j)dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
				else dp[i][j]=dp[j][i]=0;
			}
		}
	}
}
signed main(){
	cin>>n>>m;
	memset(dp,INF,sizeof(dp));
	for (int i=1;i<=m;++i){
		int a,b,c;
		cin>>a>>b>>c;
		dp[a][b]=dp[b][a]=min(dp[a][b],c);	//防止重边 
	}
	floyd();
	for (int i=1;i<=n;++i){
		for (int j=1;j<=n;++j){
			cout<

你可能感兴趣的:(学习)