Uva 10537 过路费(加强版) (Dijkstra)

n条边的无向图,由起点向终点运送货物。每进入一个村庄需要缴纳1个货物,进入一个城镇每20单位货物需要缴纳1个货物。

求过路费最少的路线。


从终点逆向用一次Dijkstra就好了。

问题的关键是路径的花费cast的计算。由A到B,若B是村庄,则cast=1,若B是城镇,则cast=(d[B]+18)/19。

设d[u]为进入城镇后最少需要的货物数量。

因为d[A]-(d[A]/20+(d[A]%20!=0))=d[A]-(d[A]+19)/20=d[B] ,即有 d[A]=20*(d[B]+18)/19, cast=d[A]-d[B]=(d[B]+18)/19


#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define maxn 55
typedef long long LL;
struct HeapNode{ //优先队列结点
    LL d;
    int u;
    bool operator < (const HeapNode& rhs) const{
        return d>rhs.d;
    }
};

struct Edge{    //边
    int from,to,dist;
};

LL P;

struct Dijkstra{
    int n,m;    //点数和边数
    vector<Edge> edges; //边列表
    vector<int> G[maxn]; //每个结点出发的边编号(从0开始)
    bool done[maxn];    //是否已永久标号
    LL d[maxn];    //s到各个点的距离
    int p[maxn];    //最短路中的上一条边

    void init(int n){
        this->n=n;
        for(int i=0;i<=n;++i) G[i].clear();//清空邻接表
        edges.clear();//清空边表
    }

    void addEdge(int from,int to,int dist){
        edges.push_back((Edge){from,to,dist});
        m=edges.size();
        G[from].push_back(m-1);
    }

    void dijkstra(int s){   //求s到所有点的最短距离
        priority_queue<HeapNode> Q;
        for(int i=0;i<=n;++i) d[i]=INF;
        d[s]=P;
        memset(done,0,sizeof(done));
        Q.push((HeapNode){P,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]];
                LL cast;
                if(u<26) cast=(d[u]+18LL)/19LL;
                else cast=1;
                if(d[e.to]>d[u]+cast){
                    d[e.to]=d[u]+cast;
                    p[e.to]=u;
                    Q.push(HeapNode{d[e.to],e.to});
                }
                else if(d[e.to]==d[u]+cast&&p[e.to]>p[u]){
                    p[e.to]=u;
                    Q.push(HeapNode{d[e.to],e.to});
                }
            }
        }
    }

    void output(int s,int e,vector<int>& path){
        int pos=s;
        while(1){
            path.push_back(pos);
            if(pos==e) break;
            pos=p[pos];
        }
    }
};

int toint(char x){
    if(x>='A'&&x<='Z') return x-'A';
    else return x-'a'+26;
}
int main()
{
    int ca=1,n,m,i,j,x,y,z;
    char a,b;
    while(~scanf("%d",&n)&&n!=-1)
    {
        Dijkstra D;
        D.init(maxn-1);
        for(i=1;i<=n;++i){
            cin>>a>>b;
            x=toint(a),y=toint(b);
            D.addEdge(x,y,0);
            D.addEdge(y,x,0);
        }
        scanf("%lld %c %c",&P,&a,&b);
        printf("Case %d:\n",ca++);
        D.dijkstra(toint(b));
        printf("%lld\n",D.d[toint(a)]);
        vector<int> path;
        D.output(toint(a),toint(b),path);
        for(i=0;i<path.size()-1;++i)
            if(path[i]<26) printf("%c-",path[i]+'A');
            else printf("%c-",path[i]+'a'-26);
        if(path[i]<26) printf("%c\n",path[i]+'A');
        else printf("%c\n",path[i]+'a'-26);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值