K - Candies (差分约束+最短路)

本文深入探讨了两种求解最短路径的经典算法:SPFA(Shortest Path Faster Algorithm)和Dijkstra算法。通过实例讲解了如何使用这两种算法解决具体问题,并提供了详细的C++代码实现,包括使用栈的SPFA算法和基于堆优化的Dijkstra算法。

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

有n个孩子,m个关系;关系分别有3个数u,v,w。代表v的糖果数不能多于u    w个,也就是dis[v]<=dis[u]+w;这就转换成

if(dis[v]>dis[u]+w)            dis[v]=dis[u]+w.

1:SPFA+stack

#include<iostream>
#include<queue>
#include<stack>
#include<cstring>
#include<stdio.h>
const int maxn=150050;   //15W条边
const int INF=0x3f3f3f3f;
using namespace std;
struct Edge
{
    int u,v,w,next;
} e[maxn];
const int N=50050;        //5W个点
int head[N],vis[N];
int dis[N];

int j,n,m;
void Init()    //初始化
{
    j=1;
    memset(head,-1,sizeof(head));
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
}
void add(int u,int v,int w)  //前向星优化存图
{
    e[j].v=v;
    e[j].w=w;
    e[j].next=head[u];
    head[u]=j++;
}
void SPFA(int s)  
{
    dis[s]=0;
    stack<int>S;
    S.push(s);
    while(!S.empty())
    {
        int u=S.top();
        S.pop();
        vis[u]=0;
        for(int i=head[u]; i!=-1; i=e[i].next)  //遍历以u为起点的所有边
        {
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].w)      //差分约束的应用,实际上就是最短路的变形呀
            {
                dis[v]=dis[u]+e[i].w;
                if(vis[v])
                    continue;
                vis[v]=1;
                S.push(v);
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);         //用cin就TLE,只有1组测试数据!!!
    Init();
    for(int i=1; i<=m; i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    SPFA(1);
    cout<<dis[n]<<endl;
    return 0;
}

2:Heap_Dijkstra
 

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<queue>
#include<stack>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=150050;    //15W条边
const int N=30050;        //3W个点
int n,m,cnt;
int head[N],dis[N],vis[N];
struct Edge
{
    int v,w,next;
} e[maxn];
struct node
{
    int s,d;            //编号和最短距离
    //node(int _s=0,int _d=0):s(_s),d(_d){}
    bool operator <(const node &r)const
    {
        return d>r.d;
    }
};
void Init()
{
    cnt=1;
    memset(head,-1,sizeof(head));
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
}
void add(int u,int v,int w)
{
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
void Heap_Dijkstra(int s)
{
    dis[s]=0;
    priority_queue<node>que;
    que.push((node)
    {
        s,0
    });   //s为定点编号,0为最短距离
    while(!que.empty())
    {
        node temp=que.top();
        que.pop();
        int u=temp.s;
        if(vis[u])
            continue;
        vis[u]=1;
        for(int i=head[u]; i!=-1; i=e[i].next)
        {
            int v=e[i].v;
            int w=e[i].w;
            if(!vis[v]&&dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                que.push((node)
                {
                    v,dis[v]
                });
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    Init();
    for(int i=1; i<=m; i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    Heap_Dijkstra(1);
    cout<<dis[n]<<endl;
    return 0;
}

3:Heap_Dijkstra 的pair表示

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<queue>
#include<stack>
using namespace std;
typedef pair<int,int>P;    //first最短距离,second定点编号
const int INF=0x3f3f3f3f;
const int maxn=150050;    //15W条边
const int N=30050;        //3W个点
int n,m,cnt;
int head[N],dis[N],vis[N];
struct Edge
{
    int v,w,next;
} e[maxn];
void Init()
{
    cnt=1;
    memset(head,-1,sizeof(head));
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
}
void add(int u,int v,int w)
{
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
void Heap_Dijkstra(int s)
{
    dis[s]=0;
    priority_queue<P,vector<P>,greater<P> >que;
    que.push((P)
    {
        0,s
    });   //0为最短距离,s为定点编号
    while(!que.empty())
    {
        P temp=que.top();
        que.pop();
        int u=temp.second;
        if(vis[u])
            continue;
        vis[u]=1;
        for(int i=head[u]; i!=-1; i=e[i].next)
        {
            int v=e[i].v;
            int w=e[i].w;
            if(!vis[v]&&dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                que.push((P)
                {
                    dis[v],v
                });
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    Init();
    for(int i=1; i<=m; i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    Heap_Dijkstra(1);
    cout<<dis[n]<<endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值