bzoj-1579: [Usaco2009 Feb]Revamping Trails 道路升级
1579: [Usaco2009 Feb]Revamping Trails 道路升级
Time Limit: 10 Sec Memory Limit: 64 MBDescription
每天,农夫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
Solution
用二维数组dis[i][j]表示1到i点用了j次道路升级后的最短路。
相当于建了一个分层图,除了第0层,每个点的dis值由上一层或所在的这一层更新而来,因为dijstra(很久都不会dijstra了,今天又去学了一下,觉得dijstra和SPFA的区别就是,dijstra用最小的dis去更新其它的dis,SPFA则不保证)每次找到最小的dis去更新其它的dis,所以第一次到达n号节点找到的就是最短路。
看到别人的题解里说SPFA要麻烦一点,需要跑k次,我不知道为什么SPFA不能像dijstra一样用二维的呐。
#include<algorithm> #include<iostream> #include<cstring> // #include<cstdlib> #include<cstdio> #include<queue> #define nn 10010 #define mm 100010 using namespace std; int e=0,k; int dis[nn][25],fir[nn],nxt[mm],to[mm],w[mm]; struct node{ int x,k,d; bool operator<(const node&b)const{ //priority——queue需要重载小于号 return d>b.d; } }; priority_queue<node> q; int read() { int ans=0,f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {ans=ans*10+ch-'0';ch=getchar();} return ans*f; } void add(int u,int v,int ww) { nxt[++e]=fir[u];fir[u]=e;to[e]=v;w[e]=ww; nxt[++e]=fir[v];fir[v]=e;to[e]=u;w[e]=ww; } int dijstra(int n) { memset(dis,127,sizeof(dis)); q.push((node){1,0,0}); dis[1][0]=0; while(!q.empty()) { node o=q.top();q.pop(); if(o.d!=dis[o.x][o.k]) continue; if(o.x==n) return o.d; for(int i=fir[o.x];i;i=nxt[i]) { if(dis[to[i]][o.k]>dis[o.x][o.k]+w[i]) { dis[to[i]][o.k]=dis[o.x][o.k]+w[i]; q.push((node){to[i],o.k,dis[to[i]][o.k]}); } if(o.k<k&&dis[to[i]][o.k+1]>dis[o.x][o.k]) { dis[to[i]][o.k+1]=dis[o.x][o.k]; q.push((node){to[i],o.k+1,dis[to[i]][o.k+1]}); } } } } int main() { int n,m,u,v,ww; n=read();m=read();k=read(); for(int i=1;i<=m;i++) { u=read();v=read();ww=read(); add(u,v,ww); } printf("%d",dijstra(n)); return 0; }