图论之最短路问题题目集

本文详细介绍了各种最短路径算法,包括Dijkstra、堆优化Dijkstra、Bellman-Ford、SPFA等,并提供了多源最短路算法如Floyd。通过实例解析,展示了如何在不同场景下运用这些算法解决实际问题,如热浪、信使、香甜的黄油、昂贵的聘礼等。此外,还讨论了带限制条件的最短路求解策略,如通信线路和最优贸易问题。
摘要由CSDN通过智能技术生成

注意事项
1.最短路问题的难点不在于算法,而在于建图方式
2.需要挖掘题目中隐藏的条件单、双向图,是否存在负环,是否有重边等等
3.往往不只简单图论还会和其他知识点一起出

第一部分————模板

一.单源最短路

dijkstra算法

注意:边权必须为非负

1.Dijkstra求最短路 I

稠密图用邻接矩阵

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510;
int g[N][N];
int dist[N];
bool st[N];
int n,m;
int dij()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    for(int i=0;i<n;i++)
    {
        int t=-1;
        for(int j=1;j<=n;j++)
        {
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
            {
                t=j;
            }
        }
        st[t]=true;
        
        for(int j=1;j<=n;j++)
        {
            dist[j]=min(dist[j],dist[t]+g[t][j]);
        }
    }
    if(dist[n]==0x3f3f3f3f)return -1;
    return dist[n];
    
}
int main()
{
    int a,b,c;
    cin>>n>>m;
    memset(g,0x3f,sizeof g);
    while (m -- )
    {
        cin>>a>>b>>c;
        g[a][b]=min(g[a][b],c);
    }
    cout<<dij()<<endl;
}
2.堆优化版的dijkstra
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1000010;
int e[N],ne[N],w[N],h[N],idx;
int n,m;
bool st[N];
int dist[N];

void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dij()
{
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    heap.push({0,1});
    while(heap.size())
    {
        auto t=heap.top();
        heap.pop();
        int ver=t.second;
        if(st[ver])continue;
        st[ver]=true;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[ver]+w[i])
            {
                dist[j]=dist[ver]+w[i];
                heap.push({dist[j],j});
            }
        }
    }
    if(dist[n]>=0x3f3f3f3f/2)return -1;
    else return dist[n];
    
}
int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof h);
    int a,b,c;
    while (m -- ){
        cin>>a>>b>>c;
        add(a,b,c);
    }
    cout<<dij()<<endl;
}
3.有边数限制的最短路 bellman-ford算法
边权可以为负数
可以用来找负环,第n次有更新的话证明有负环
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010;
struct Edge{
    int a,b,c;
}ed[N];
int n,m,k;
int dist[N];
int last[N];
void ford()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    for(int i=0;i<k;i++)
    {
        memcpy(last,dist,sizeof dist);
        for(int j=0;j<m;j++)
        {
            auto e=ed[j];
            dist[e.b]=min(dist[e.b],last[e.a]+e.c);
        }
    }
}
int main()
{
    cin>>n>>m>>k;
    int a,b,c;
    for(int i=0;i<m;i++)
    {
        cin>>a>>b>>c;
        ed[i]={a,b,c};
    }
    ford();
    if(dist[n]>0x3f3f3f3f/2)cout<<"impossible"<<endl;
    else cout<<dist[n]<<endl;
}
5.有负权求最短路 spfa算法
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int N = 100010;
int e[N],ne[N],h[N],w[N],idx=0;
int dist[N];
bool st[N];
int n,m;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int spfa()
{
    queue<int>q;
    q.push(1);
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    st[1]=true;
    while(q.size())
    {
        auto t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
                dist[j]=dist[t]+w[i];
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return dist[n];
}
int main()
{
    cin>>n>>m;
    memset(h, -1, sizeof h);
    int a,b,c;
    while (m -- )
    {
        cin>>a>>b>>c;
        add(a,b,c);
    }
    int res=spfa();
    if(res==0x3f3f3f3f)cout<<"impossible"<<endl;
    else cout<<res<<endl;
}

6.spfa求负环

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010;
int e[N],ne[N],w[N],h[N],idx=0;
bool st[N];
int n,m;
int dist[N];
int cnt[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa()
{
    queue<int>q;
    for(int i=1;i<=n;i++)
    {
        q.push(i);
        st[i]=true;
    }
    while(q.size())
    {
        auto t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n)return true;
                dist[j]=dist[t]+w[i];
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return false;
}
int main()
{
    cin>>n>>m;
    int a,b,c;
    memset(h,-1,sizeof h);
    while (m -- )
    {
        cin>>a>>b>>c;
        add(a,b,c);
    }
    if(spfa())cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
}

二.多源汇最短路

1.floyd算法

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 210;
const int INF = 0x3f3f3f3f;
int n,m,q;
int d[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++)
              d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
              
}
int main()
{
    cin>>n>>m>>q;
    
    for(int i=1;i<=n;i++)
       for(int j=1;j<=n;j++)
          if(i==j)d[i][j]=0;
          else d[i][j]=INF;
    
    int a,b,c;
    while (m -- )
    {
        cin>>a>>b>>c;
        d[a][b]=min(d[a][b],c);
    }
    floyd();
    
    while(q--)
    {
        cin>>a>>b;
        int t=d[a][b];
        if(t>0x3f3f3f3f/2)cout<<"impossible"<<endl;
        else cout<<t<<endl;
    }
}

第二部分————练习题

1.热浪----dijkstra

链接

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

typedef pair<int, int> PII;
typedef long long LL;
const int N = 6220*2,M=2520;
int dist[M];
bool st[M];
int h[M],e[N],w[N],ne[N],idx=0;
int n,m,ss,ee;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

int dij(int ss,int ee)
{
    memset(dist,0x3f,sizeof dist);
   // priority_queue<PII, vector<PII>, greater<PII> > heap;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0,ss});
    dist[ss]=0;
    while(heap.size())
    {
        auto t=heap.top();
        heap.pop();
        int ver=t.second;
        if(st[ver])continue;
        st[ver]=true;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[ver]+w[i])
            {
                dist[j]=dist[ver]+w[i];
                heap.push({dist[j],j});
            }
        }
    }
    return dist[ee];
}

int main()
{
    memset(h, -1, sizeof h);
    cin>>n>>m>>ss>>ee;
    int a,b,c;
    while (m -- ){
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    cout<<dij(ss,ee)<<endl;
}

2.信使----floyd

链接

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 210;
int d[N][N];
int n,m;
int main()
{
    int a,b,c;
    cin>>n>>m;
    memset(d,0x3f,sizeof d);
    d[1][1]=0;
    
    while (m -- ){
        cin>>a>>b>>c;
        d[a][b]=d[b][a]=min(d[a][b],c);
    }
    
    
    for(int k=1;k<=n;k++)
       for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
             d[i][j]=min(d[i][k]+d[k][j],d[i][j]);
             
    int res=0;
    
    for(int i=2;i<=n;i++)
    {
        if(d[1][i]==0x3f3f3f3f)
        {
            cout<<"-1"<<endl;
            return 0;
        }
        else res=max(res,d[1][i]);
    }
    cout<<res<<endl;
}

3.香甜的黄油----dijkstra

链接

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;

const int N = 3000;
int e[N],h[N],w[N],ne[N],idx=0;
int dist[N],id[N];
bool st[N];
int n,p,m;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dij(int ss)
{
    memset(st,0,sizeof st);
    memset(dist,0x3f,sizeof dist);
    priority_queue<PII,vector<PII>,greater<PII>>q;
    q.push({0,ss});
    dist[ss]=0;
    
    while(q.size())
    {
        auto t=q.top();
        q.pop();
        
        int ver=t.second;
        if(st[ver])continue;
        st[ver]=true;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[ver]+w[i])
            {
                dist[j]=dist[ver]+w[i];
                q.push({dist[j],j});
            }
        }
    }
    int res=0;
    for(int i=1;i<=n;i++)
    {
        if(dist[id[i]]==0x3f3f3f3f)return 0x3f3f3f3f;
        else
        res+=dist[id[i]];
    }
    return res;
}

int main()
{
    cin>>n>>p>>m;
    memset(h,-1,sizeof h);
    int x;
    for(int i=1;i<=n;i++)
    {
        cin>>id[i];
    }
    int a,b,c;
    while (m -- )
    {
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    int res=0x3f3f3f3f;
    for(int i=1;i<=p;i++)
    {
        res=min(res,dij(i));
    }
    cout<<res<<endl;
}

4.最小花费----朴素版dijkstra

链接

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 2010;
int n,m,ss,tt;
double g[N][N];
double dist[N];
bool st[N];
void dij()
{
    dist[ss]=1;
    for(int i=1;i<=n;i++)
    {
        int t=-1;
        for(int j=1;j<=n;j++)
        {
            if(!st[j]&&(t==-1||dist[t]<dist[j]))
            {
                t=j;
            }
        }
        
        st[t]=true;
        for(int j=1;j<=n;j++)
        {
            dist[j]=max(dist[j],dist[t]*g[t][j]);
        }
    }
}
int main()
{
    cin>>n>>m;
    int a,b,c;
    while (m -- )
    {
        cin>>a>>b>>c;
        double t=(100.0-c)/100.0;
        g[a][b]=g[b][a]=max(g[a][b],t);
    }
    cin>>ss>>tt;
    dij();
    printf("%.8lf\n",100/dist[tt]);
}

5.最优乘车----bfs+建图

链接

#include <iostream>
#include <cstring>
#include <algorithm>
#include <sstream>
using namespace std;
const int N = 1000;
int g[N][N];
int n,m;
int dist[N],q[N];
int cnt=0;
int stop[N]; 
void bfs()
{
    int hh=0,tt=-1;
    memset(dist,0x3f,sizeof dist);
    q[++tt]=1;
    dist[1]=0;
    while(hh<=tt)
    {
        auto t=q[hh++];
        
        for(int i=1;i<=n;i++)
        {
            if(g[t][i]&&dist[i]==0x3f3f3f3f)
            {
                dist[i]=dist[t]+1;
                q[++tt]=i;
            }
            
        }
    }
}
int main()
{
    cin>>m>>n;
    string s;
    getline(cin,s);
    while (m -- )
    {
        getline(cin,s);
        stringstream ssin(s);
        int p,cnt=0;
        while(ssin>>p)stop[cnt++]=p;
        for(int i=0;i<cnt;i++)
           for(int j=i+1;j<cnt;j++)
              g[stop[i]][stop[j]]=true;
        
    }
    bfs();
    if(dist[n]==0x3f3f3f3f)cout<<"NO"<<endl;
    else cout<<max(dist[n]-1,0)<<endl;
}

6.昂贵的聘礼----朴素版dijkstra+有限制的建图方式+虚拟原点

题目链接

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110,INF=0x3f3f3f3f;
int g[N][N];
int level[N];
int dist[N];
bool st[N];
int n,m;
int dij(int ss,int ee)
{
    memset(st, 0, sizeof st);
    memset(dist,0x3f,sizeof dist);
    dist[0]=0;
    for(int i=0;i<=n;i++)
    {
        int t=-1;
        for(int j=0;j<=n;j++)
        {
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
            {
                t=j;
            }
        }
        st[t]=true;
        
        for(int j=1;j<=n;j++)
        {
            if(level[j]>=ss&&level[j]<=ee)
            {
                dist[j]=min(dist[j],dist[t]+g[t][j]);
            }
        }
    }
    return dist[1];
}
int main()
{
    cin>>m>>n;
    memset(g,0x3f,sizeof g);
    for(int i=1;i<=n;i++)g[i][i]=0;
    for(int i=1;i<=n;i++)
    {
        int w,cnt;
        cin>>w>>level[i]>>cnt;
        g[0][i]=min(g[0][i],w);
        while(cnt--)
        {
            int a,b;
            cin>>a>>b;
            g[a][i]=min(g[a][i],b);
        }
        
    }
    int res=INF;
    for(int i=level[1]-m;i<=level[1];i++)res=min(res,dij(i,i+m));
    cout<<res<<endl;
}

7.新年好

算法:建图+堆优化dijkstra+dfs+暴力

链接

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 50010,M=200010;
const int INF = 0x3f3f3f3f;
int h[N],w[M],e[M],ne[M],idx=0;
bool st[N];
int dist[6][N];
int n,m;
int source[6];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dij(int ss,int dist[])
{
    memset(dist,0x3f,N*4);
    memset(st, 0, sizeof st);
    priority_queue<PII,vector<PII>,greater<PII> >q;
    dist[ss]=0;
    q.push({0,ss});
    while(q.size())
    {
        auto t=q.top();
        q.pop();
        int ver=t.second;
        if(st[ver])continue;
        st[ver]=true;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[ver]+w[i])
            {
                dist[j]=dist[ver]+w[i];
                q.push({dist[j],j});
            }
        }
    }
}
int dfs(int u,int ss,int distance)
{
    if(u>5)return distance;
    int res=INF;
    for(int i=1;i<=5;i++)
    {
        
        if(!st[i])
        {
            int next=source[i];
            st[i]=true;
            res=min(dfs(u+1,i,distance+dist[ss][next]),res);
            st[i]=false;
        }
    }
    return res;
}
int main()
{
    memset(h,-1,sizeof h);
    cin>>n>>m;
    for(int i=1;i<6;i++)cin>>source[i];
    source[0]=1;
    while (m -- ){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    for(int i=0;i<6;i++)dij(source[i],dist[i]);
    
    memset(st,0,sizeof st);
    cout<<dfs(1,0,0)<<endl;
}

8.通信线路

最大值最小一般都可以二分来做
这题的难点在于对结果的限制条件k,求结果最大值最小,用二分,把大于答案的边长度设为1,小于答案的边为0,求0,1路径可用双端队列求解,是代码更加简练
链接

#include <iostream>
#include <cstring>
#include <algorithm>
#include <deque>
using namespace std;
const int N = 1010,M=20010;
int h[N],w[M],e[M],ne[M],idx=0;
int n,p,k;
int dist[N];
bool st[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool check(int bound)
{
    memset(st, 0, sizeof st);
    memset(dist,0x3f,sizeof dist);
    
    deque<int>q;
    q.push_back(1);
    dist[1]=0;
    
    while(q.size())
    {
        int t=q.front();
        q.pop_front();
        
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i],x=w[i]>bound;
            if(dist[j]>dist[t]+x)
            {
                dist[j]=dist[t]+x;
                if(!x)q.push_front(j);
                else q.push_back(j);
            }
        }
        
    }
    return dist[n]<=k;
}
int main()
{
    memset(h,-1,sizeof h);
    cin>>n>>p>>k;
    int a,b,c;
    while(p--)
    {
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    int l=0,r=1e6+1;
    while(l<r)
    {
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    if(r==1e6+1)cout<<-1<<endl;
    else cout<<r<<endl;
}

9.道路与航线–dfs+topsort+dijkstra+建图方式

算法流程

1.先输入所有双向道路,然后DFS出所有连通块,计算两个数组:id[]存储每个点属于哪个连通块;vector<int> block[]存储每个连通块里有哪些点:
2.输入所有航线,同时统计出每个连通块的入度。
3.按照拓扑序依次处理每个连通块,先将所有入度为0的连通块的编号加入队列
中。
4.每次从队头取出一个连通块的编号bid
5.将该block[bid]中的所有点加入堆中,然后对堆中所有点跑dijkstra算法。
6.每次取出堆中距离最小的点ver
7.然后遍历ver的所有邻点j。如果id[ver]==id[],那么如果j能被更新,则将j插入堆中:如果id[ver]!= id[j],则将id[j]这个连通块的入度减1,如果减成0了,则将其插入拓扑排序的队列中

题目链接

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
#define x first
#define y second

const int N = 25010,M=150010;
int h[N],e[M],ne[M],w[M],idx=0;

int dist[N];
bool st[N];
vector<int>block[N];
int bcnt=0;
int id[N];
int n,rm,pm,s;
int din[N];
queue<int>q;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int bid)
{
    id[u]=bid;
    block[bid].push_back(u);
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!id[j])
        {
            dfs(j,bid);
        }
    }
}
void dij(int bid)
{
    memset(st, 0, sizeof st);
    priority_queue<PII,vector<PII>,greater<PII> >heap;
    
    for(auto u:block[bid])
    {
        heap.push({dist[u],u});
    }
    
    while(heap.size())
    {
        auto t=heap.top();
        heap.pop();
        
        int ver=t.second;
        if(st[ver])continue;
        st[ver]=true;
        
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(id[j]!=id[ver]&&--din[id[j]]==0)q.push(id[j]);
            if(dist[j]>dist[ver]+w[i])
            {
                dist[j]=dist[ver]+w[i];
                if(id[j]==id[ver])heap.push({dist[j],j});
            }
        }
        
    }
}
void topsort()
{
    memset(dist,0x3f,sizeof dist);
    dist[s]=0;
    for(int i=1;i<=bcnt;i++)
    {
        if(din[i]==0)
        {
            q.push(i);
        }
    }
    while(q.size())
    {
        int t=q.front();
        q.pop();
        dij(t);
    }
}
int main()
{
    memset(h,-1,sizeof h);
    cin>>n>>rm>>pm>>s;
    int a,b,c;
    while(rm--)
    {
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    
    for(int i=1;i<=n;i++)
    {
        if(!id[i])
        {
            dfs(i,++bcnt);
        }
    }
    
    while(pm--)
    {
        cin>>a>>b>>c;
        din[id[b]]++;
        add(a,b,c);
    }
    topsort();
    for(int i=1;i<=n;i++)
    {
        if(dist[i]>0x3f3f3f3f/2)cout<<"NO PATH"<<endl;
        else cout<<dist[i]<<endl;
    }
}

10.最优贸易

题目链接

双spfa同时进行
先求出:

1 走到 i的过程中,买入水晶球的最低价格 dmin[i]
i走到 n 的过程中,卖出水晶球的最高价格 dmax[i]
然后枚举每个城市作为买卖的中间城市,求出 dmax[i] - dmin[i]的最大值即可。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010,M=2000010;
int h[N],rh[N],e[M],ne[M],idx=0;
int n,m;
int dist[N];
bool st[N];
int dmax[N],dmin[N];
void add(int h[],int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void spfa(int d[],int start,int h[],bool flag)
{
    queue<int>q;
    memset(st,0,sizeof st);
    if(flag)memset(d,0x3f,sizeof dmin);
    q.push(start);
    d[start]=dist[start];
    st[start]=true;
    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(flag&&d[j]>min(d[t],dist[j])||!flag&&d[j]<max(d[t],dist[j]))
            {
                if(flag){
                    d[j]=min(d[t],dist[j]);
                }
                else d[j]=max(d[t],dist[j]);
                
                if(!st[j])
                {
                    st[j]=true;
                    q.push(j);
                }
            }
        }
    }
}

int main()
{
    cin>>n>>m;
    memset(h, -1, sizeof h);
    memset(rh,-1,sizeof rh);
    for(int i=1;i<=n;i++)cin>>dist[i];
    while (m -- )
    {
        int a,b,c;
        cin>>a>>b>>c;
            add(h,a,b);
            add(rh,b,a);
        if(c==2)
        {
            add(h,b,a);
            add(rh,a,b);
        }
    }
    
    spfa(dmin,1,h,true);
    spfa(dmax,n,rh,false);
    
    int res=0;
    for(int i=1;i<=n;i++)res=max(res,dmax[i]-dmin[i]);
    cout<<res<<endl;
}

11.选择最佳线路

添加链接描述

稠密图,用邻接矩阵,建立超级原点。
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
int n,m,s;
const int N = 1010;
int g[N][N];
bool st[N];
int dist[N];
void dij()
{
    memset(st,0,sizeof st);
    
    dist[0]=0;
    
    for(int i=1;i<=n;i++)
    {
        int t=-1;
        for(int j=0;j<=n;j++)
        {
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
            {
                t=j;
            }
        }
        st[t]=true;
        for(int i=1;i<=n;i++)
        {
            dist[i]=min(dist[i],dist[t]+g[t][i]);
        }
    }
    
}
int main()
{
    int a,b,c,x,cnt;
    while(~scanf("%d%d%d",&n,&m,&s))
    {
        memset(g,0x3f,sizeof g);
        memset(dist,0x3f,sizeof dist);
        while (m -- )
        {
            cin>>a>>b>>c;
            g[a][b]=min(g[a][b],c);
        }
        cin>>cnt;
        for(int i=0;i<cnt;i++)
        {
            cin>>x;
            g[0][x]=0;
        }
        dij();
        if(dist[s]==0x3f3f3f3f)cout<<-1<<endl;
        else cout<<dist[s]<<endl;
    }
}

12.最短路计数

题目链接

这道题比较新奇,同时使用bfs时不需要设置st数组,类似于spfa的松弛操作
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int N = 100010,M=400010;
const int mod = 100003;
int h[N],e[M],ne[M],idx=0;
int dist[N];
int n,m;
int cnt[N];
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs()
{
    memset(dist,0x3f,sizeof dist);
    cnt[1]=1;
    dist[1]=0;
    queue<int>q;
    q.push(1);
    while(q.size())
    {
        int t=q.front();
        q.pop();
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+1)
            {
                dist[j]=dist[t]+1;
                cnt[j]=cnt[t];
                q.push(j);
            }
            else if(dist[j]==dist[t]+1)
            {
                cnt[j]=(cnt[j]+cnt[t])%mod;
            }
        }
    }
    
}
int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof h);
    int a,b;
    while (m -- ){
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    bfs();
    for(int i=1;i<=n;i++)cout<<cnt[i]<<endl;
}

13.牛的旅行

多源汇最短路Floyd算法

题目链接

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;
#define x first
#define y second

typedef pair<double, double> PDD;
const int N = 155;
PDD q[N];
const double INF = 1e20;
double d[N][N];
int n;
double maxd[N];
char g[N][N];
double get_dist(PDD a,PDD b)
{
    double dx=a.x-b.x;
    double dy=a.y-b.y;
    return sqrt(dx*dx+dy*dy);
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
          cin>>q[i].x>>q[i].y;
          
    for(int i=0;i<n;i++)cin>>g[i];
    
    for(int i=0;i<n;i++)
       for(int j=0;j<n;j++)
          {
              if(i==j)d[i][j]=0;
              else if(g[i][j]=='1')d[i][j]=get_dist(q[i],q[j]);
              else d[i][j]=INF;
          }
          
    for(int k=0;k<n;k++)
       for(int i=0;i<n;i++)
          for(int j=0;j<n;j++)
             d[i][j]=min(d[i][k]+d[k][j],d[i][j]);
    
    double res1=0;
    for(int i=0;i<n;i++)
    {
       for(int j=0;j<n;j++)
          if(d[i][j]<INF/2)maxd[i]=max(maxd[i],d[i][j]);
          
          res1=max(maxd[i],res1);
     
    }      
    double res2=INF;
    
    for(int i=0;i<n;i++)
       for(int j=0;j<n;j++)
          if(d[i][j]>INF/2)
          {
              res2=min(res2,maxd[i]+maxd[j]+get_dist(q[i],q[j]));
          }
    printf("%.6lf",max(res1,res2));
}

14.排序

多源汇最短路Floyd算法
#include <iostream>
#include <cstring>
#include <algorithm>
#include<cstdio>
using namespace std;
const int N = 26;
int n,m;
bool g[N][N],d[N][N];
bool st[N];
void floyd(){
    memcpy(d,g,sizeof d);
    for(int k=0;k<n;k++)
       for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
           d[i][j]|=d[i][k]&&d[k][j];
}
int check(){
    for(int i=0;i<n;i++)
       if(d[i][i])
         return 2;
    for(int i=0;i<n;i++)
       for(int j=0;j<i;j++)
          if(!d[i][j]&&!d[j][i])
             return 0;
    return 1;
    
}
char get_min(){
    for(int i=0;i<n;i++)
        if(!st[i]){
            bool flag=true;
            for(int j=0;j<n;j++)
               if(!st[j]&&d[j][i]){
                   flag=false;
                   break;
               }
            if(flag){
                st[i]=true;
                return 'A'+i;
            }
        }
}
int main()
{
    while(cin>>n>>m,n||m){
        memset(g,0,sizeof g);
        int type=0,t;
        for(int i=1;i<=m;i++){
            char str[5];
            cin>>str;
            int a=str[0]-'A',b=str[2]-'A';
            if(!type){
                g[a][b]=1;
                floyd();
                type=check();
                if(type)t=i;
            }
        }
        if(!type)puts("Sorted sequence cannot be determined.");
        else if(type==2)printf("Inconsistency found after %d relations.\n", t);
        else {
            memset(st, 0, sizeof st);
            printf("Sorted sequence determined after %d relations: ", t);
            for(int i=0;i<n;i++)printf("%c",get_min());
            printf(".\n");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_WAWA鱼_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值