Revamping Trails 道路翻新
- Description
农场里有N个牛棚,编号为1到N。它们之间由M条双向道路连接,第i条道路连接的牛棚为 P1i 和 P2i ,通行时间为 Ti 。约翰每天都要检查牛棚里的奶牛,他会从编号为1牛棚出发,通过最短的路线走到编号为N的牛棚。为了节约时间,约翰打算翻新K条道路,被翻新后的道路可以快速通过,通行时间视作0。请帮助约翰选择最好的翻新方法使得从1号牛棚到N号 牛棚的通行时间最短。
- Input Format
第一行:三个用空格分开的整数:
N
,
- Output Format
第一行:翻新后的最短通行时间,输入数据保证终点一定可达
- Sample Input
4 4 1
1 2 10
2 4 10
1 3 1
3 4 100
- Sample Output
1
- Hint
选择翻新3→4,通行时间从100变成0,最短路径为1→3→4,因而总用时为1。
- 分析
因为K只有20的范围,所以我们可以从K入手。我们把一个点拆成K+1个点,分别表示走到这个点时已翻新了若干条道路,然后跑Spfa。
之后你会发现TLE,所以要堆优化。
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
int n,m,k,u,v,w,x,tot,ans=1<<30,last[10010],dist[21][10010],bo[21][10010];
struct info{
int to,next,val;
}e[100010];
struct Date{
int x,u;
};
inline bool operator < (const Date&a,const Date&b){return dist[a.x][a.u]>dist[b.x][b.u];}
priority_queue <Date> q;
void addline(int u,int v,int w){
e[++tot].to=v; e[tot].val=w; e[tot].next=last[u]; last[u]=tot;
e[++tot].to=u; e[tot].val=w; e[tot].next=last[v]; last[v]=tot;
}
int main(){
freopen("in.txt","r",stdin);
freopen("out1.txt","w",stdout);
scanf("%d %d %d\n",&n,&m,&k);
for (int i=1;i<=m;i++){
scanf("%d %d %d\n",&u,&v,&w);
addline(u,v,w);
}
for (int i=0;i<=k;i++)
for (int j=0;j<=n;j++)
dist[i][j]=1<<30;
q.push((Date){0,1});
bo[0][1]=1;
dist[0][1]=0;
int cas=0;
for (;!q.empty();){
x=q.top().x,u=q.top().u; q.pop(); cas++;
bo[x][u]=0;
for (int i=last[u];i;i=e[i].next){
v=e[i].to,w=e[i].val;
if (dist[x][u]+w<dist[x][v]){
dist[x][v]=dist[x][u]+w;
if (bo[x][v]==0){
bo[x][v]=1; q.push((Date){x,v});
}
}
if (x+1<=k && dist[x][u]<dist[x+1][v]){
dist[x+1][v]=dist[x][u];
if (bo[x+1][v]) continue;
bo[x+1][v]=1; q.push((Date){x+1,v});
}
}
}
printf("%d",dist[k][n]);
fclose(stdin); fclose(stdout);
}