bzoj 1579: [Usaco2009 Feb]Revamping Trails 道路升级
Description
每天,农夫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的时间尽量少.
Input
* 第一行: 三个空格分开的数: N, M, 和 K * 第2..M+1行: 第i+1行有三个空格分开的数:P1_i, P2_i, 和 T_i
Output
* 第一行: 更新最多K条路经后的最短路经长度.
Sample Input
4 4 1
1 2 10
2 4 10
1 3 1
3 4 100
1 2 10
2 4 10
1 3 1
3 4 100
Sample Output
1
HINT
K是1; 更新道路3->4使得从3到4的时间由100减少到0. 最新最短路经是1->3->4,总用时为1单位. N<=10000
思路:这个题目比较简单,直接列点,把状态表示成二维,然后用最短路径算法求出。
注意本题卡spfa,用可以堆优化的dijsktra来做。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int const N=100000+3; 4 int const M=20+1; 5 long long const inf=1e12; 6 #define ll long long 7 int vis[N][M],n,m,K,h[N],cnt; 8 ll d[N][M]; 9 struct edge { 10 int to,nt,w; 11 } e[N<<2]; 12 struct node { 13 int x,y; 14 ll d; 15 bool operator < (const node &rhs) const { 16 return d>rhs.d; 17 } 18 }; 19 priority_queue<node> q; 20 void add(int a,int b,int c) { 21 e[++cnt].to=b; 22 e[cnt].w=c; 23 e[cnt].nt=h[a]; 24 h[a]=cnt; 25 } 26 ll dijsktra() { 27 for(int i=1; i<=n; i++) 28 for(int j=0; j<=K; j++) 29 d[i][j]=inf; 30 d[1][0]=0; 31 node t=(node){1,0,0}; 32 q.push(t); 33 while (!q.empty()) { 34 int x=q.top().x; 35 int y=q.top().y; 36 q.pop(); 37 if(vis[x][y]) continue; 38 vis[x][y]=1; 39 for(int i=h[x]; i; i=e[i].nt) { 40 int v=e[i].to; 41 if(d[v][y]>d[x][y]+e[i].w && !vis[v][y] ) { 42 d[v][y]=d[x][y]+e[i].w; 43 node t=(node){v,y,d[v][y]}; 44 q.push(t); 45 } 46 if(y+1<=K && d[v][y+1]>d[x][y] && !vis[v][y+1]) { 47 d[v][y+1]=d[x][y]; 48 node t=(node){v,y+1,d[v][y+1]}; 49 q.push(t); 50 } 51 } 52 } 53 ll ans=inf; 54 for(int i=0; i<=K; i++) 55 ans=min(ans,d[n][i]); 56 return ans; 57 } 58 int main() { 59 scanf("%d%d%d",&n,&m,&K); 60 while (m--) { 61 int x,y,z; 62 scanf("%d%d%d",&x,&y,&z); 63 add(x,y,z); 64 add(y,x,z); 65 } 66 printf("%lld\n",dijsktra()); 67 return 0; 68 }