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;
}