BZOJ:2763-[JLOI2011]飞行路线(最短路分层图)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2763
解题心得:
- 第一次见到分层最短路。其实题中说选择k条路径免费,那怎么选k条路径并没有一个明确的选法,就只能遍历。分层图就是一个图分成k层,每个节点可以走当前层的相邻节点,费用为cost,但是也可以走下一层的相邻节点,费用为0,因为只有k层,所以从第0层的S到达第k层的T也就走了k个免费路径。这个时候K不能太大,不然容易MLE。
#include <stdio.h> #include <cstring> #include <algorithm> #include <queue> #include <vector> using namespace std; typedef long long ll; const int maxn = 5e5+100; const ll INF = 1e12; ll n, m, k, S, T; struct edge { ll to, len; edge(ll to1, ll len1): to(to1), len(len1){}; }; struct NODE {//记录队列中节点的位置,层数,花费 ll len, pos, c; bool friend operator < (NODE a, NODE b) { return a.len > b.len; } NODE (ll len1, ll pos1, ll c1): len(len1), pos(pos1), c(c1){}; }; vector <edge> ve[maxn]; ll dis[11][maxn]; void add_edge(ll u, ll v, ll len) {//注意是双向边 ve[u].push_back(edge(v, len)); ve[v].push_back(edge(u, len)); } void init() { for(int i=0;i<11;i++) for(int j=0;j<maxn;j++) dis[i][j] = INF; scanf("%lld%lld%lld",&n,&m,&k); scanf("%lld%lld",&S, &T); for(int i=0;i<m;i++) { ll u, v, len; scanf("%lld%lld%lld",&u, &v, &len); add_edge(u, v, len); } } void dij() {//用dij不容易被卡网格图 priority_queue <NODE> qu; qu.push(NODE(0, S, 0)); dis[0][S] = 0; while(!qu.empty()) { NODE now = qu.top(); qu.pop(); ll u = now.pos; for(int i=0;i<ve[u].size();i++) {//走当前层 ll v = ve[u][i].to; ll len = ve[u][i].len; ll c = now.c; if(dis[c][v] > dis[c][u]+len) { dis[c][v] = dis[c][u] + len; qu.push(NODE(dis[c][v], v, c)); } } ll c = now.c; if(c < k) {//走下一层 for (int i = 0; i < ve[u].size(); i++) { ll v = ve[u][i].to; if(dis[c+1][v] > dis[c][u]) {//花费为0 dis[c+1][v] = dis[c][u]; qu.push(NODE(dis[c][u], v, c+1)); } } } } } void min_path() { dij(); ll Min = INF; for(int i=0;i<=k;i++) { Min = min(Min, dis[i][T]); } printf("%lld\n", Min); } int main() { init(); min_path(); }