【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;
}

 

posted @ 2017-03-01 19:40  GXZlegend  阅读(261)  评论(0编辑  收藏  举报