您的位置:首页 > Web前端

【USACO】2009 Feb Revamping Trails 道路翻新

2016-10-31 09:33 330 查看

Revamping Trails 道路翻新

Description

农场里有N个牛棚,编号为1到N。它们之间由M条双向道路连接,第i条道路连接的牛棚为P1i和P2i,通行时间为Ti。约翰每天都要检查牛棚里的奶牛,他会从编号为1牛棚出发,通过最短的路线走到编号为N的牛棚。为了节约时间,约翰打算翻新K条道路,被翻新后的道路可以快速通过,通行时间视作0。请帮助约翰选择最好的翻新方法使得从1号牛棚到N号 牛棚的通行时间最短。

Input Format

第一行:三个用空格分开的整数: N,M和K,1≤N≤10000,K≤M≤50000,1≤K≤20,第二行到M+1行:在第i+1行有三个用空格分开的整数:P1i,P2i和Ti,表示第i条道路的情况,1≤P1i,P2i≤N,1≤Ti≤106

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]
);
fclose(stdin); fclose(stdout);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: