<题目>
Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?
<算法>
分层图最短路 堆优化的Dijkstra
<分析>
乍一看是最短路,再仔细一看用最短路似乎无法实现。分层图可以很巧妙的解决这个问题。想象你每次使用免费航线之前和之后分别存在于不同的时空(不同的层)里面,每使用一次免费航线,你就从这个时空进入了另一个时空(免费)。根据以上思想建图,一共建k+1层图,相邻的两层图中进行连边(单向边,距离为1)。然后跑dijkstra即可
<注意>
-
分层图思想~
-
spfa会超时。我用的是stl里面的priority_queue写堆j。注意priority_queue里面不用front()而是top。而且需要重定义结构体的operator<
<鸣谢>
感谢zky的题解
<代码>
/**************************************************************
Problem: 2763
User: gaotianyu1350
Language: C++
Result: Accepted
Time:512 ms
Memory:38320 kb
****************************************************************/
#include
#include
#include
#include
#include
#include
using namespace std; #define MAXNODE 200100 #define MAXEDGE 3000000 #define INF 1000000000 struct Node { int dis,u; bool operator<(const Node x)const { return dis>x.dis; } }; int point[MAXNODE]={0},w[MAXEDGE],next[MAXEDGE]={0},v[MAXEDGE],tot; int dis[MAXNODE]; bool check[MAXNODE]; priority_queue
q; int n,m,k; void addedge(int x,int y,int cost) { tot++; next[tot]=point[x];point[x]=tot;v[tot]=y;w[tot]=cost; } int dijkstra(int s,int t) { memset(dis,0x7f,sizeof(dis)); memset(check,0,sizeof(check)); while (!q.empty()) q.pop(); dis[s]=0;q.push((Node){0,s}); while (!q.empty()) { Node now=q.top();q.pop(); if (check[now.u]) continue; check[now.u]=true; for (int temp=point[now.u];temp;temp=next[temp]) if (dis[now.u]+w[temp]