Papa的魔法靴子 (原BZOJ 2662)
在Papa所在的魔法大陆上,有N个城市,M条双向的道路。大魔法师Papa准备开始休假了,在1号城市的他,准备去第N号城市旅行,他想尽快的到达N市,这样他就可以花更多是时间去和老朋友们见面。
Papa有一双魔法靴子,他的魔法靴子可以施法K次,每次施法可以使他的速度快一倍。这也就是说,在通过某条路径时,我们可以选择施一次法,这样,我们通过这一条道路的时间就可以减少到原先的一半。需要注意的是:
1. 在一条道路上最多只能施法一次。
2. 每次施法只在一条道路上起作用。
3. 没有必要把K次施法都用完。
给定以上的信息,你的任务是:求出在可以使用这不超过 K 次的魔法靴子之情形下,从城市1 到城市N最少需要多长时间。
Input
第一行包含三个整数:N、M、K。
接下来 M 行,每行包含三个整数:Ai、Bi、Ti,表示存在一条 Ai与 Bi之
间的双向道路,在不施法的前提下,通过它需要 Ti的时间。
Output
输出一个整数,表示从1 号城市到 N号城市的最小用时。
Sample Input
4 4 1
1 2 4
4 2 6
1 3 8
3 4 8
Sample Output
7
【样例1 解释】
在不施法时,最短路为 1->2->4,总时间为 10。现在我们可以施法一次,那么我们将通过 2->4 这条道路的时间减半,此时总时间为7。
HINT
对于100%的数据:1 ≤
K ≤ N ≤ 50,M ≤ 1000。
1≤ Ai,Bi ≤ N,2 ≤ Timei
≤ 2000。
为保证答案为整数,保证所有的 Timei均为偶数。
所有数据中的无向图保证无自环、重边,且是连通的。
定义两个结构体:
struct Edge{ //存边,不解释
int from,to,val,next;
}edge[MX];
struct Sta{ //状态,到某位置时的花费
int arr,cos;
};
我们用一个二维数组 dis[i][j] 表示到 i 位置花费 j 个代价,同时以状态建队:queue<Sta> q;
SPFA:(分两种情况)
1.不施法
用了 j 次法力到达 i -> 更新 -> 入队
2.施法
判断 j < t(是否还可以施法)-> 更新 -> 入队
代码如下
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std; int n,m,k,dis[101][101],first[101]; bool vis[101][101]; struct Edge{ int to,val,next; }edge[2002]; struct Sta{ int pos,cos; }; int cnt; void add(int from,int to,int val) { edge[++cnt].to=to; edge[cnt].val=val; edge[cnt].next=first[from]; first[from]=cnt; } void Spfa() { queue<Sta> q; memset(dis,0x3f,sizeof(dis)); dis[1][0]=0; vis[1][0]=1; q.push((Sta){1,0}); while(!q.empty()) { Sta cur=q.front();q.pop(); int pos=cur.pos; int cost=cur.cos; for(int i=first[pos];i;i=edge[i].next) { int to=edge[i].to; if(dis[pos][cost]+edge[i].val<dis[to][cost]) { dis[to][cost]=dis[pos][cost]+edge[i].val; if(!vis[to][cost]){ vis[to][cost]=1; q.push((Sta){to,cost}); } } } if(cost<k) { for(int i=first[pos];i;i=edge[i].next) { int to=edge[i].to; if(dis[pos][cost]+(edge[i].val>>1) < dis[to][cost+1]) { dis[to][cost+1]=dis[pos][cost]+(edge[i].val/2); if(!vis[to][cost+1]){ vis[to][cost+1]=1; q.push((Sta){to,cost+1}); } } } } } int ans=0x3f3f3f3f; for(int i=0;i<=k;++i) ans=min(ans,dis[n][i]); printf("%d",ans); } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;++i){ int from,to,val; scanf("%d%d%d",&from,&to,&val); add(from,to,val); add(to,from,val); } Spfa(); return 0; }