最短路

1.floyd算法

可以预处理出任意点之间的最短路,如果最短路的起点和终点总是改变,用这个比较方便

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

2.Dijstra算法:

堆优化的可以解决从a点出发去任意点的最短路径,无法处理含负权边的图

dijstra算法堆优化:(模板题)链接:https://www.luogu.org/problem/P3371

#include
#define ll long long
#define inf 2147483647
#define MAXN 500005
using namespace std;
int to[MAXN<<1],head[MAXN<<1],nxt[MAXN<<1],val[MAXN<<1];
int tot=0;
ll dis[MAXN];
int vis[MAXN];

void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
}

void add(int u,int v,int w)
{
    to[++tot]=v;
    val[tot]=w;
    nxt[tot]=head[u];
    head[u]=tot;
}
struct node
{
    int v;
    ll dis;
    friend bool operator<(node a,node b)
    {
        return a.dis>b.dis;
    }
};

void dij(int st,int n)
{
    for(int i=0;i que;
    que.push(node{st,0});
    while(que.size())
    {
        int u=que.top().v;
        que.pop();
        if(vis[u]==1)
            continue;
        vis[u]=1;
        for(int i=head[u];~i;i=nxt[i])
        {
            int v=to[i];
            if(dis[u]+val[i]

输出路径

用pre[]保存路径,如果更新了u->v,呢么最后一次v被更新,即为到v的路径

//更新路径的时候,pre[v]=u;
void print(int x,int y)
{
    int u=x,v=y;
    printf("%d",u);
    while(u!=v)
    {
        printf("->%d",pre[u]);
        u=pre[u];
    }
    printf("\n");
}

3,SPFA算法:

如果图中含有负权边,呢么我们用spfa算法(广搜)解决:

#include
#define ll long long
#define MAXN 1000005
using namespace std;
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN<<1],val[MAXN<<1];
int tot=0;
ll dis[MAXN];

void init()
{
    memset(head,0,sizeof(head));
    tot=0;
}

void add(int u,int v,int w)
{
    to[++tot]=v;
    nxt[tot]=head[u];
    val[tot]=w;
    head[u]=tot;
}

void spfa(int st,int n)
{
    for(int i=0;i<=n;i++)
        dis[i]=1e18;
    queue que;
    dis[st]=0;
    que.push(st);
    while(que.size())
    {
        int u=que.front();
        que.pop();
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(dis[u]+val[i]

判负环:如果图中存在负环,spfa会一直进行下去,一般判负环的题

https://www.luogu.org/problem/P3385

#include
#define ll long long
#define MAXN 20005
using namespace std;
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN<<1],val[MAXN<<1];
int tot=0,sign;
int vis[MAXN];
int n,dis[MAXN],cnt[MAXN];

void init()
{
    sign=tot=0;
    for(int i=0;i<=MAXN;i++)
        cnt[i]=vis[i]=head[i]=0,dis[i]=1e9;
}

void add(int u,int v,int w)
{
    to[++tot]=v;
    nxt[tot]=head[u];
    val[tot]=w;
    head[u]=tot;
}

int spfa()
{
	queue q;
	q.push(1);
	dis[1]=0;
	while(!q.empty())
    {
		if(dis[q.front()]>dis[q.back()])
            swap(q.front(),q.back());
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=nxt[i])
        {
			int v=to[i];
			if(dis[v]>dis[u]+val[i])
			{
				dis[v]=dis[u]+val[i];
				cnt[v]=cnt[u]+1;
				if(cnt[v]>n)
                    return 1;
				if(!vis[v])
				{
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	return 0;
}

int main()
{
    int m,t,u,v,w;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            if(w>=0)
                add(v,u,w);
        }
        if(spfa())
            printf("YE5\n");
        else
            printf("N0\n");
    }
    return 0;
}

k短路算法(A* 算法)

(沈阳网络赛):

#include
#define maxn 1005
#define maxe 100005
using namespace std;
 
struct State{
    int f,g,u;  // f=g+dis dis表示当前点到终点的最短路径,即之前的预处理,g表示到当前点的路径长度
    bool operator<(const State b)const{
        if(f==b.f)return g>b.g;
        return f>b.f;
    }
};
 
struct Edge{
    int v,w,next;
}edge[maxe],reedge[maxe];
 
int head[maxn],rehead[maxn];
int dis[maxn],vis[maxn];
int n,m,cot,s,t,k;
 
void init(){
    cot=0;    //cot代表边的id  每条边的id都不相同
    memset(head,-1,sizeof(head));
    memset(rehead,-1,sizeof(rehead));
}
 
void addedge(int u,int v,int w){
    edge[cot]={v,w,head[u]};//记录上一次u的id是多少 这样方便遍历head[u]初始值为-1
    head[u]=cot;//head[u]  给这个u标记上独一无二的id
    reedge[cot]={u,w,rehead[v]};
    rehead[v]=cot++;
}
 
void SPFA(){
    queueq;
    memset(vis,0,sizeof(vis));
    memset(dis,-1,sizeof(dis));
    int u,v;
    q.push(t);
    vis[t]=true;//vis表示当前点是否在队列
    dis[t]=0;
    while(!q.empty()){
        u=q.front();
        q.pop();
        vis[u] = 0;//rehead[u] 是u最后一次出现的id  reedge[i].ne  代表第i次出现的边上一次出现的id
        for(int i=rehead[u];~i;i=reedge[i].next){  //~i取反 当i为-1时正好取反为0 退出for
            v=reedge[i].v;
            if(dis[v]>dis[u]+reedge[i].w || dis[v]==-1){
                dis[v]=dis[u]+reedge[i].w;
                if(!vis[v]){
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
}
 
int Astart(){
    if(s==t)k++;
    if(dis[s]==-1)return -1;
    int cnt=0;
    priority_queueq; // 优先队列
    State a,b;
    a.g=0;
    a.u=s;
    a.f=a.g+dis[a.u];
    q.push(a);
    while(!q.empty()){
        b=q.top();
        q.pop();
        if(b.u==t){
            cnt++;
            if(cnt==k)return b.g;
        }
        for(int i=head[b.u];~i;i=edge[i].next){
            a.g=b.g+edge[i].w;
            a.u=edge[i].v;
            a.f=a.g+dis[a.u];
            q.push(a);
        }
    }
    return -1;
}
 
int main()
{
    int u,v,w,T;
    while(scanf("%d%d",&n,&m)==2){
        init();
        scanf("%d%d%d%d",&s,&t,&k, &T);  //起点 终点 第k条 时间T
        for(int i=0;i

 

你可能感兴趣的:(最短路径算法)