山東理工大學2020年全國天梯賽賽前個人專題強化賽---C(最短路)

ccccvvvvvcv發表於2020-12-31

在這裡插入圖片描述
在這裡插入圖片描述
旅遊規劃這個題,其實用floyd也可以做,而且程式碼看起來更舒服,先給一個floyd的程式碼(非全原創,侵刪),但要注意,由於floyd確實多算了很多無用的資料,如果卡你時間,floyd是過不了的。

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f

int node [505][505];
int dis[505][505];
int main()
{
    int n,m,s,d,i,j,k,x,y,q,w;
    cin>>n>>m>>s>>d;
    memset(dis,INF,sizeof(dis));
    memset(node,INF,sizeof(node));
    for(int i=0;i<n;i++)
    {
    dis[i][i]=0;
    node[i][i]=0;
    }
    for(i=0; i<m; i++)
    {
        scanf("%d %d %d %d",&x,&y,&q,&w);
        node[x][y] = node[y][x] = q;
        dis[x][y] = dis[y][x] = w;
    }
    for(k=0; k<n; k++)
    {
        for(i=0; i<n; i++)
        {
            for(j=0; j<n; j++)
            {
                if(node[i][j]>node[i][k]+node[k][j]||(node[i][j]==node[i][k]+node[k][j]&&dis[i][j]>dis[i][k]+dis[k][j]))
                {
                    node[i][j] = node[i][k]+node[k][j];
                    dis[i][j] = dis[i][k]+dis[k][j];
                }
            }
        }
    }
    printf("%d %d\n",node[s][d],dis[s][d]);
    return 0;
}

dijkstra演算法(非全原創,侵刪)

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f;
using namespace std;

int n,m,s,d;
int G[505][505];
int a[505][505];
int lowcost[505];
int fee[505];
int vis[505];
void dij()
{
    for(int i=0;i<n;i++)
    {
        lowcost[i]=INF;
    }
    lowcost[s]=0;
    for(int mm=0;mm<n;mm++)
    {
        int minn=INF;
        int k=-1;
        for(int i=0;i<n;i++)
        {
            if(lowcost[i]<=minn && vis[i]==0)
            {
                minn=lowcost[i];
                k=i;
            }
        }
        vis[k]=1;
        for(int i=0;i<n;i++)
        {
                if(vis[i]==0&&lowcost[i]==lowcost[k]+G[k][i]) //不寫vis[i]==0也對,但是會浪費時間
                {
                    if(fee[i]>fee[k]+a[k][i])
                    {
                        fee[i]=fee[k]+a[k][i];
                    }
                }
                else if(vis[i]==0&&lowcost[i]>lowcost[k]+G[k][i])
                {
                    lowcost[i]=lowcost[k]+G[k][i];
                    fee[i]=fee[k]+a[k][i];
                }
        }
    }
}


int main()
{
    scanf("%d %d %d %d",&n,&m,&s,&d);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i!=j)
                G[i][j]=G[j][i]=INF;
        }
    }
    while(m--)
    {
        int x,y,l,f;
        scanf("%d %d %d %d",&x,&y,&l,&f);
        G[x][y]=G[y][x]=l;
        a[x][y]=a[y][x]=f;
    }
    dij();
    printf("%d %d\n",lowcost[d],fee[d]);
    return 0;
}

在這裡插入圖片描述
在這裡插入圖片描述
城市間緊急救援這個題我認為比上面那個考的更加全面和具體,比如他要求輸出路徑,要求輸出最短路徑條數,比起上個題,此題更有挑戰性,做出來收穫更大。
程式碼是我在網上找的,因為很好,比我自己的好太多,所以我只改了一個變數名,侵刪。

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;

int a[1001][1001];
int cnt[1001],vis[1001]= {0},cf[1001],ccf[1001],pre[1001];
//最短路徑條數,各城市是否經過,各城市的救援隊數量,到達該城市時所召集的所有救援隊數量,到達該城市前經過的城市編號
int n,m,s,d;
int Dijkstra()
{
    cnt[s]=1;//開始時路徑條數為1
    vis[s]=1;//當前在出發城市
    for(int i=0; i<n; i++)
    {
        int min=inf,f=-1;
        for(int j=0; j<n; j++)
        {
            if(vis[j]==0&&a[s][j]<min) //尋找下一個距離最短的城市
            {
                min=a[s][j];
                f=j;//做好下一城市編號的標記
            }
        }
        if(f==-1)break;//與其他未經過的城市不連通,退出迴圈
        else vis[f]=1;//到達下一城市
        for(int j=0; j<n; j++)
        {
            if(vis[j]==0&&a[s][j]>a[s][f]+a[f][j]) //到達某一城市的最短路徑
            {
                a[s][j]=a[s][f]+a[f][j];//最短路徑更新
                pre[j]=f;//記錄上一個城市編號
                cnt[j]=cnt[f];//拷貝到達上一個城市時的最短路徑條數
                ccf[j]=ccf[f]+cf[j];//到達某城市召集的全部救援隊數量
            }
            else if(vis[j]==0&&a[s][j]==a[s][f]+a[f][j]) //發現其他的最短路徑
            {
                cnt[j]=cnt[j]+cnt[f];//更新到達當前城市時的最短路徑條數
                if(ccf[j]<ccf[f]+cf[j]) //最多救援隊數量更新
                {
                    pre[j]=f;//記錄所經過的上一個城市編號
                    ccf[j]=ccf[f]+cf[j];//更新救援隊總數
                }
            }
        }
    }
}


int main()
{
    cin>>n>>m>>s>>d;
    for(int i=0; i<n; i++)
    {
        cin>>cf[i];
        ccf[i]=cf[i];
        cnt[i]=1;
    }
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            if(i!=j)a[i][j]=a[j][i]=inf;//初始化(雙向圖)
        }
    }
    for(int i=0; i<m; i++)
    {
        int q,w,e;
        cin>>q>>w>>e;
        a[q][w]=a[w][q]=e;
    }
    Dijkstra();
    cout<<cnt[d]<<" "<<ccf[d]+cf[s]<<endl;//注意ccf[d]要與cf[s]相加
    int road[1001];
    int x=0,t=d;
    while(pre[t]!=0) //所經歷的城市的從後往前的順序
    {
        road[x++]=pre[t];
        t=pre[t];
    }
    cout<<s;//出發地
    for(int i=x-1; i>=0; i--)
        cout<<" "<<road[i];
    cout<<" "<<d;//目的地
}


相關文章