UVA 10537 The Toll! Revisited 过路费(最短路,经典变形)

时间:2022-08-03 06:35:36

题意:给一个无向图,要从起点s运送一批货物到达终点e,每个点代表城镇/乡村,经过城镇需要留下(num+19)/20的货物,而经过乡村只需要1货物即可。现在如果要让p货物到达e,那么从起点出发最少要准备多少货物?输出答案和路径(多条路径则必须输出字典序最小的)。注:终点需要花费,而起点不需要。

思路:这最短路变形的不错。要逆推过来求最短路径,那么就从e出发到s的距离!只是p比较大,而且城镇还得推出前一站到底需要多少货物,既然直接计算那么麻烦,也可以一直p++直到能留下p为止就推出来了;而乡村就容易推了,只是+1。但是还有个字典序要解决,则在碰到dist[u]==dist[v]+距离的时候就比较一下字典序谁小就记谁。

  有一点别忘了,这是在逆推!!所以你要用出发点去更新终点时,要以出发点的dist来比较字典序。无向边是要建两条有向的,防止重边。

 #include <bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define INF 0x7f7f7f7f
using namespace std;
const int N=;
int n, m, l, edge_cnt;
LL p;
vector<int> vect[N];
struct node
{
int from, to;
node(){};
node(int from,int to):from(from),to(to){};
}edge[]; void add_node(int from,int to)
{
edge[edge_cnt]=node(from, to);
vect[from].push_back(edge_cnt++);
} LL dist[N];
int path[N], vis[N];
LL dijkstra(int s,int e)
{
memset(path, , sizeof(path));
memset(vis, , sizeof(vis));
memset(dist, 0x7f, sizeof(dist)); priority_queue<pii,vector<pii>,greater<pii> > que;
que.push(make_pair(p,s));
dist[s]=p; while(!que.empty())
{
int x=que.top().second;que.pop();
if(vis[x]) continue;
vis[x]=; bool flag=isupper(x); //大写,花费多的
LL t=dist[x]+(dist[x]+)/;
while(t-(t+)/<dist[x]) t++; //注意不要超时 for(int i=; i<vect[x].size(); i++)
{
node e=edge[vect[x][i]];
if( flag )
{
if(dist[e.to]>=t)
{
if(dist[e.to]==t)
{
if( x<edge[path[e.to]].from ) path[e.to]=vect[x][i]; //字典序
}
else path[e.to]=vect[x][i]; dist[e.to]=t;
que.push(make_pair(dist[e.to],e.to));
}
}
else
{
if(dist[e.to]>=dist[x]+)
{
if(dist[e.to]==dist[x]+)
{
if( x<edge[path[e.to]].from ) path[e.to]=vect[x][i]; //字典序
}
else path[e.to]=vect[x][i]; dist[e.to]=dist[x]+;
que.push(make_pair(dist[e.to],e.to));
}
}
}
}
return dist[e];
} void cal(int s,int e)
{
cout<<dijkstra(s,e)<<endl;
vector<char> ans;
int ed=e;
while(ed!=s)
{
ans.push_back( ed );
int t=path[ed];
ed=edge[t].from;
}
ans.push_back(s);
printf("%c",ans[]);
for(int i=; i<ans.size(); i++) printf("-%c",ans[i]);
cout<<endl;
} int main()
{
freopen("input.txt", "r", stdin);
char a, b;
int j=;
while(scanf("%d", &n), n>=)
{
edge_cnt=;
memset(edge,,sizeof(edge));
for(int i=; i<N; i++) vect[i].clear();
int up=;
for(int i=; i<n; i++)
{
getchar();
scanf("%c %c",&a,&b); //%c会接收到换行!!
add_node(a, b);
add_node(b, a);
}
scanf("%lld %c %c",&p, &a, &b);
printf("Case %d:\n",++j);
cal(b, a);
}
return ;
}

AC代码