【bzoj1579】[Usaco2009 Feb]Revamping Trails 道路升级 分层图最短路
题目描述
每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M. 道路i连接牛棚P1_i和P2_i (1 <= P1_i <= N; 1 <= P2_i<= N). John需要T_i (1 <= T_i <= 1,000,000)时间单位用道路i从P1_i走到P2_i或者从P2_i 走到P1_i 他想更新一些路经来减少每天花在路上的时间.具体地说,他想更新K (1 <= K <= 20)条路经,将它们所须时间减为0.帮助FJ选择哪些路经需要更新使得从1到N的时间尽量少.
输入
* 第一行: 三个空格分开的数: N, M, 和 K * 第2..M+1行: 第i+1行有三个空格分开的数:P1_i, P2_i, 和 T_i
输出
* 第一行: 更新最多K条路经后的最短路经长度.
样例输入
4 4 1
1 2 10
2 4 10
1 3 1
3 4 100
样例输出
1
题解
分层图最短路
dis[i][j]为更新j条路径时1到i的最短距离。
然后跑分层图最短路。
网上说正解是堆优化Dijkstra,然而我不太会写,只好搞了一个双端队列优化Spfa才勉强卡时过。
#include <cstdio> #include <cstring> #include <utility> #include <queue> using namespace std; deque<pair<int , int> > q; int head[50010] , to[100010] , next[100010] , cnt , inq[50010][21]; long long len[100010] , dis[50010][21]; void add(int x , int y , long long z) { to[++cnt] = y; len[cnt] = z; next[cnt] = head[x]; head[x] = cnt; } int main() { int n , m , k , i , j , x , y; long long z , ans = 0x3f3f3f3f3f3f3f3fll; pair<int , int> u , tmp; scanf("%d%d%d" , &n , &m , &k); for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%lld" , &x , &y , &z) , add(x , y , z) , add(y , x , z); memset(dis , 0x3f , sizeof(dis)); dis[1][0] = 0; q.push_front(make_pair(1 , 0)); while(!q.empty()) { u = q.front(); q.pop_front(); x = u.first , y = u.second; inq[x][y] = 0; for(i = head[x] ; i ; i = next[i]) { for(j = 0 ; j <= 1 ; j ++ ) { if(y + j <= k && dis[to[i]][y + j] > dis[x][y] + len[i] * (j ^ 1)) { dis[to[i]][y + j] = dis[x][y] + len[i] * (j ^ 1); if(!q.empty()) tmp = q.front(); if(!q.empty() && dis[to[i]][y + j] < dis[tmp.first][tmp.second]) q.push_front(make_pair(to[i] , y + j)); else q.push_back(make_pair(to[i] , y + j)); } } } } for(i = 0 ; i <= k ; i ++ ) ans = min(ans , dis[n][i]); printf("%lld\n" , ans); return 0; }