版权声明:欢迎转载,若转载,请标明出处,如有错误,请指点,也欢迎大佬们给出优化方法 https://blog.csdn.net/Charles_Zaqdt/article/details/86561053
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3499
题意是有n个城市,m条路线,然后有一张半价票,问从起点到终点的最小花费。
这道题如果不知道分层图的话很容易会想到一种错误的解法,就是跑一遍最短路,然后将最大的权值/2,可以自己试着造几个样例试试这样是不对的(比如最短路相同,但是路径不同的情况),所以这道题用分层图去跑,因为只有一张半价票,所以只需要建两层图就好了。因为如果可以到达终点的话,这张半价票肯定是要用的,所以最终的结果就一定是ma[s]到ma[t] + n,至于建图的过程看代码自己理解吧。(用的是链式前向星存图方式,所以对于边数应该是题目要求的3倍)
AC代码:
#include <bits/stdc++.h>
#define maxn 100005 << 1
#define maxm 500005 << 2
#define ll long long
const ll inf = 0x3f3f3f3f3f3f3f3f;
using namespace std;
struct Node{
int to, next, w;
bool operator < (const Node &a) const{
return a.w < w;
}
}Edge[maxm], Now, Next;
int head[maxn],num;
ll dist[maxn];
bool vis[maxn];
int n,m;
void init(){
for(int i=0;i<=n*2;i++) head[i] = -1;
num = 0;
}
void add(int u,int v,int w){
Edge[num].to = v;
Edge[num].w = w;
Edge[num].next = head[u];
head[u] = num ++;
}
void dijkstra(int s){
for(int i=0;i<=2*n;i++){
dist[i] = inf;
vis[i] = false;
}
dist[s] = 0;
priority_queue<Node> q;
Now.to = s;
q.push(Now);
while(!q.empty()){
int u = q.top().to;
q.pop();
if(vis[u]) continue;
vis[u] = true;
for(int i=head[u];i!=-1;i=Edge[i].next){
int v = Edge[i].to;
if(!vis[v] && dist[v] > dist[u] + Edge[i].w){
dist[v] = dist[u] + Edge[i].w;
Next.to = v;
Next.w = dist[v];
q.push(Next);
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)){
init();
map<string,int> ma;
int pos = 1;
int w;
char u[15],v[15],s[15],t[15];
for(int i=0;i<m;i++){
scanf("%s%s%d",u,v,&w);
if(!ma[u]) ma[u] = pos ++;
if(!ma[v]) ma[v] = pos ++;
add(ma[u], ma[v], w);
add(ma[u] + n, ma[v] + n, w);
add(ma[u], ma[v] + n, w / 2);
}
scanf("%s%s",s,t);
if( !ma[s] || !ma[t]){
puts("-1");
continue;
}
dijkstra(ma[s]);
printf("%lld\n", dist[ma[t] + n] == inf ? -1 : dist[ma[t] + n]);
}
return 0;
}