UVA10537[The Toll! Revisited] dijkstra/spfa 反向建图

本文介绍了一种使用图算法解决特定货物运输问题的方法。该问题涉及在一个包含城市和村庄的混合网络中找到从起点到终点运送货物的最优路径。文章详细阐述了如何构建图模型,采用Dijkstra算法及其变体进行最短路径计算,并考虑了通过城市和村庄的不同费用条件。

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

题目链接


题意:给定一个无向图,大写字母是城市,小写字母是村庄,经过城市交过路费为当前货物的%5,路过村庄固定交1,给定起点终点和到目标地点要剩下的货物,问最少要带多少货物上路,并输出路径,如果有多种方案,要求字典序最小


solution:反向建图, d[i]表示从i到终点需要的数量。

#include <map>
#include <cmath>
#include <queue>
#include <vector> 
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 105;
const long long Inf = (1LL<<61);
struct Edge{
    int u, v, w;
    Edge(int u, int v, int w):u(u),v(v),w(w){}
}; 
struct HeapNode{
    long long d;int u;
    bool operator<(const HeapNode& rhs) const{
        return d>rhs.d;
    }
};

char to[255];

struct Dijkstra{
    int n, m;
    long long d[N];
    bool done[N];
    vector<Edge> edges;
    vector<int> G[N];
    int p[N];
    void init(int n){
        this->n=n;
        for ( int i=0; i<n; i++ ) G[i].clear();
        edges.clear(); 
    }
    void addeage(int u, int v, int w){
        edges.push_back((Edge){u,v,w});
        m=edges.size();
        G[u].push_back(m-1);
    }
    void print(int u){
        if( p[u]==-1 ){
            printf("%c\n", to[u]);
            return;
        }
        printf("%c-", to[u] );
        print(edges[p[u]].u);
    }
    void dijkstra(int s, long long vl){
        for ( int i=0; i<n; i++ ) d[i]=Inf, done[i]=0;
        d[s]=vl;
        p[s]=-1;
        priority_queue<HeapNode> Q;
        Q.push((HeapNode){vl,s});
        while( !Q.empty() ){
            HeapNode x=Q.top(); Q.pop();
            int u=x.u;
            if( done[u] ) continue;
            done[u]=1;
            for ( int i=0; i<G[u].size(); i++ ){
                Edge& e=edges[G[u][i]];
                long long nd;
                if( e.w ) nd= (long long) ceil(d[u]*1.0/19*20);
                else nd=d[u]+1;
                if( d[e.v]>nd || d[e.v]==nd && to[u]<to[edges[p[e.v]].u] ){
                    d[e.v]=nd;
                    p[e.v]=G[u][i];
                    Q.push((HeapNode){d[e.v],e.v});
                }
            }
        }

    }
};

struct SPFA{
    int n, m;
    long long d[N];
    bool inq[N];
    int p[N];
    vector<Edge> edges;
    vector<int> G[N];
    void init(int n){
        this->n=n;
        for ( int i=0; i<n; i++ ) G[i].clear();
        edges.clear();
    }
    void addeage(int u, int v, int w){
        edges.push_back((Edge){u,v,w});
        m=edges.size();
        G[u].push_back(m-1);
    }
    void print(int u){
        if( p[u]==-1 ){
            printf("%c\n", to[u] );
            return ;
        }
        printf("%c-", to[u] );
        print(edges[p[u]].u);
    }
    void spfa(int s, long long vl){
        for ( int i=0; i<n; i++ ) d[i]=Inf, inq[i]=0;
        d[s]=vl;
        p[s]=-1;
        queue<int> Q;
        Q.push(s);
        while( !Q.empty() ){
            int u=Q.front(); Q.pop();
            inq[u]=0;
            for ( int i=0; i<G[u].size(); i++ ){
                Edge& e=edges[G[u][i]];
                long long nd;
                if( e.w ) nd=(long long) ceil(d[u]*1.0/19*20);
                else nd=d[u]+1;
                if( d[e.v]>nd || d[e.v]==nd && to[u]<to[edges[p[e.v]].u] ){
                    d[e.v]=nd;
                    p[e.v]=G[u][i];
                    if( !inq[e.v] ){
                        inq[e.v]=1;
                        Q.push(e.v);
                    }
                }
            }
        }
    }
};
SPFA D;
int vis[255];
int main(){
    for ( int i=0; i<26; i++ ) {
        vis['a'+i]=i+26; to[i+26]='a'+i;
        vis['A'+i]=i; to[i]='A'+i;
    }
    int n, m, kas=0;
    while( scanf("%d", &m ) == 1 && m!=-1 ){
        D.init(52);
        char a[2], b[2];
        for ( int i=1; i<=m; i++ ){
            scanf("%s%s", a, b );
            int u=vis[a[0]], v=vis[b[0]];
            D.addeage(u,v,a[0]<'a');
            D.addeage(v,u,b[0]<'a');
        }
        long long vl;
        scanf("%lld%s%s", &vl, a, b );
        int u=vis[a[0]], v=vis[b[0]];
        D.spfa(v,vl);
        printf("Case %d:\n", ++kas);  
        printf("%lld\n", D.d[u]);  
        D.print(u);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值