最短路(dijkstra & folyed)

版权声明:转载请注明出处 https://blog.csdn.net/qq_39541141/article/details/83719683

最近系统的(重新)复习了一下最短路
毕竟许多题都可以转化成最短路来写

先说一下Folyed(_{n}3)

​

    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                a[i][j]=min(a[i][j],a[i][k]+a[k][j]);

​

这个算法的思路显而易见 这里不再赘述

拓展

当该图为无向图时

我们可以这么写

​

 for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=i;j++)
                a[j][i]=a[i][j]=min(a[i][j],a[i][k]+a[k][j]);

​

这个比上面那个快一倍吧

 P1828 香甜的黄油 Sweet Butter里加上这个优化就可以过QAQ

代码如下

​
​
​
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int f[804][804],a[804][804],m,n,c[888],p,x,y,z,temp,ans=999999;
inline int read()
{
    int f=1,w=0;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while('0'<=ch&&ch<='9'){w=w*10+ch-48;ch=getchar();}
    return f*w;
}
int main()
{	
    cin>>p>>n>>m;
    for(int i=1;i<=n;i++)
    for(int l=1;l<=n;l++)
    {
    	if(i==l)f[i][l]=a[i][l]=0;
    	else f[i][l]=a[i][l]=999999;
	}
	for(int i=1;i<=p;i++)
	c[i]=read();
	for(register int l=1;l<=m;l++){
		x=read(),y=read(),z=read();
		a[y][x]=a[x][y]=z;
		f[y][x]=f[x][y]=z;
    }
    for(register int i=1;i<=n;i++)
      for(register int l=1;l<=n;l++)
        for(register int j=1;j<=l;j++)
          f[l][j]=f[j][l]=min(f[j][l],f[j][i]+f[i][l]);
	for(register int i=1;i<=n;i++)
    {
    	temp=0;
        for(register int l=1;l<=p;l++)
		temp+=f[i][c[l]];
		ans=min(ans,temp);	
	}
    cout<<ans<<endl;
    return 0;
 } 

​

​

​

拓展×2

如果这张图是用坐标表示的

比如这道题吧 古韵之鹊桥相会

建图之后就用以下这种folyed去找

​
#include <bits/stdc++.h>
using namespace std;
const int maxn = 25, INF = 0x3f3f3f3f;
string s[maxn];
int n, m, res = INF, dp[maxn][maxn][maxn][maxn];
int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};

int main() {
    ios::sync_with_stdio(false);
    memset(dp, INF, sizeof(dp));
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >> s[i];
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            dp[i][j][i][j] = 0;
            for (int k = 0; k < 4; k++) {
                int x = i + dx[k], y = j + dy[k];
                if (x >= 0 && x < n && y >= 0 && y < m) {
                    dp[i][j][x][y] = (s[i][j] != s[x][y]);
                }
            }
        }
    }
    // floyd
    for (int kx = 0; kx < n; kx++) {
        for (int ky = 0; ky < m; ky++) {
            for (int ix = 0; ix < n; ix++) {
                for (int iy = 0; iy < m; iy++) {
                    for (int jx = 0; jx < n; jx++) {
                        for (int jy = 0; jy < m; jy++) {
                            dp[ix][iy][jx][jy] = min(dp[ix][iy][jx][jy], dp[ix][iy][kx][ky] + dp[kx][ky][jx][jy]);
                        }
                    }
                }
            }
        }
    }
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < m; j++) {
            res = min(res, dp[0][i][n - 1][j]);
        }
    }
    cout << res + 1 << endl;
    return 0;
}

​

(不是我的代码QAQ 在题解里面翻了一个)

也也也应该就这些了吧(我就知道这些)

Dijkstra(n log n)

终于该讲这个了QAQ

Dijkstra是目前跑的最快的单源最短路算法。

Dijkstra的适用范围:没有负权边的图。

代码如下(怎么又不讲代码???? 我我我也不会讲吖)

​
#include<iostream>
#include<algorithm>
#include<queue> 
#define maxn 100002
#define maxm 200002
using namespace std;
int head[maxn],next[maxm],to[maxm],d[maxn],w[maxm],tot,s,n;
bool v[maxn];
priority_queue<pair<int,int> >q;
inline void add(int x,int y,int z){
    next[++tot]=head[x],head[x]=tot;
    to[tot]=y,w[tot]=z;
}
void dijkstra(){
    for(register int i=1;i<=n;i++)d[i]=1e10;
    d[s]=0;q.push(make_pair(d[s],s));
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(v[x])continue; v[x]=1;
        for(register int i=head[x];i;i=next[i]){
            int y=to[i],z=w[i];
            if(d[y]>d[x]+z)
            d[y]=d[x]+z,q.push(make_pair(-d[y],y));
        }
    }
}
int main()
{
    int m,x,y,z;
    cin>>n>>m>>s;
    for(register int i=1;i<=m;i++){
        cin>>x>>y>>z;
        add(x,y,z);
    }
    dijkstra();
    for(register int i=1;i<=n;i++)cout<<d[i]<<" ";
    return 0;
}

​

拓展

如何求出最短路径有几条?

加一个语句就ok 见P1144 最短路计数

#include<iostream>
#include<queue>
#define maxn 1000002
#define maxm 2000002
using namespace std;
priority_queue<pair<int ,int> >q;
int next[maxm],head[maxn],to[maxm],w[maxm],dis[maxn],cnt,ans[maxm];
bool v[maxm];
inline void add(int x,int y){
	next[++cnt]=head[x],head[x]=cnt;
	to[cnt]=y,w[cnt]=1;
}
int main()
{
	int m,n,s=1,x,y,z;
	cin>>n>>m;
	for(register int i=1;i<=n;i++)dis[i]=1e10;
	for(register int i=1;i<=m;i++)
	{cin>>x>>y;add(x,y);add(y,x);}
	ans[s]=1,dis[s]=0,q.push(make_pair(0,s));//多了一个初始化

	while(!q.empty()){
	    int x=q.top().second;q.pop();
	    if(v[x])continue ;v[x]=1;
		for(register int i=head[x];i;i=next[i]){
			int y=to[i],z=w[i];
			if(dis[y]>z+dis[x]){
				dis[y]=dis[x]+z;
				ans[y]=ans[x];//更新最短路同时也更新路径数量
				q.push(make_pair(-dis[y],y));
			}
             //增加路径
			 else if(dis[y]==dis[x]+1){
                 ans[y]+=ans[x];
                 ans[y]%=100003;
			}
		}
	}
	for(register int i=1;i<=n;i++)cout<<ans[i]<<endl;
	return 0;
}

(也就是改了改上面的代码)

拓展×2

怎样输出路径???

也是加上几条语句

代码如下

#include<iostream>
#include<algorithm>
#include<queue> 
#define maxn 100002
#define maxm 200002
using namespace std;
int head[maxn],next[maxm],to[maxm],d[maxn],w[maxm],tot,s,n;
int road[1003][1003];
bool v[maxn];
priority_queue<pair<int,int> >q;
inline void add(int x,int y,int z){
    next[++tot]=head[x],head[x]=tot;
    to[tot]=y,w[tot]=z;
}
void dijkstra(){
    for(register int i=1;i<=n;i++)d[i]=1e10;
    d[s]=0;q.push(make_pair(d[s],s));
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(v[x])continue; v[x]=1;
        for(register int i=head[x];i;i=next[i]){
            int y=to[i],z=w[i];
            if(d[y]>d[x]+z){
            d[y]=d[x]+z;
            road[s][y]=road[x][y];//更新前驱点 
			q.push(make_pair(-d[y],y));            	
			} 
        }
    }
}
inline void prin(int x){
	if(road[s][x]==0)return ;
	prin(road[s][x]);
	cout<<"->"<<x;
}
int main()
{
    int m,x,y,z;
    cin>>n>>m>>s;
    for(register int i=1;i<=m;i++){
        cin>>x>>y>>z;
        add(x,y,z);
        road[x][y]=x;//从x到y的前驱点是x 
    }
    dijkstra();
    for(register int i=1;i<=n;i++){
	    cout<<d[i]<<"  ";
	    if(d[i])cout<<s,prin(i);
	    cout<<endl;		
	}
    return 0;
}

嗯......

先到这里吧

再附上几道题:

P4779 【模板】单源最短路径(标准版)

P1522 牛的旅行 Cow Tours

P1576 最小花费

猜你喜欢

转载自blog.csdn.net/qq_39541141/article/details/83719683
今日推荐