To_Heart—题解——JLOI2011飞行路线
题目描述
Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?
输入格式
数据的第一行有三个整数,n,m,k,分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,s,t,分别表示他们出行的起点城市编号和终点城市编号。(0<=s,t<n)
接下来有m行,每行三个整数,a,b,c,表示存在一种航线,能从城市a到达城市b,或从城市b到达城市a,价格为c。(0<=a,b<n,a与b不相等,0<=c<=1000)
输出格式
只有一行,包含一个整数,为最少花费。
样例
样例输入
5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100
样例输出
8
数据范围与提示
对于30%的数据,2<=n<=50,1<=m<=300,k=0;
对于50%的数据,2<=n<=600,1<=m<=6000,0<=k<=1;
对于100%的数据,2<=n<=10000,1<=m<=50000,0<=k<=10.
题解
乍一看,哇塞,这不是分层图最短路的板子吗???
又一看,哇塞,不会打分层图
于是采取其它的方法;
仔细一看,可以DP呀!!!
对于定义dp[i][j],表示第i点到源点使用了j次免费机会的最短路径;
那么到达dp[i][j]的方式有两种
- 由i所连接的点直接到达i;
- 由i所连接的点使用一次免费后到达i;
所以dp[i][j]=min(dp[v][j-1],dp[v][j]+w)
其中,v为所有连接i的店,w为其边权;
代码
#include<bits/stdc++.h>
using namespace std;
struct zz{
int u,w,k;
};
bool operator <(zz a,zz b){
return a.w>b.w;
}
vector<zz> v[10005];
int dp[10005][15];
bool f[10005][15];
int n,m,tot;
void Dijkstra(int st,int ed){
memset(dp,0x3f,sizeof dp);
dp[st][0]=0;
priority_queue<zz> q;
q.push(zz{st,0,0});
while(q.size()){
zz now;
now=q.top();
int nowk=now.k;
int nowans=now.w;
int u=now.u;
q.pop();
if(f[u][nowk])
continue;
f[u][nowk]=1;
for(int i=0;i<v[u].size();i++){
int u1=v[u][i].u;
int w=v[u][i].w;
if(dp[u1][nowk]>dp[u][nowk]+w&&!f[u1][nowk]){
dp[u1][nowk]=dp[u][nowk]+w;
q.push(zz{u1,dp[u1][nowk],nowk});
}
if(nowk+1<=tot){
if(dp[u1][nowk+1]>dp[u][nowk]&&!f[u1][nowk+1]){
dp[u1][nowk+1]=dp[u][nowk];
q.push(zz{u1,dp[u1][nowk+1],nowk+1});
}
}
}
}
int Min=0x3f3f3f3f;
for(int i=0;i<=tot;i++){
Min=min(Min,dp[ed][i]);
//printf("%d %d %d\n",ed,i,dp[ed][i]);
}
printf("%d",Min);
}
int main(){
int st,ed;
scanf("%d%d%d",&n,&m,&tot);
scanf("%d%d",&st,&ed);
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
v[x].push_back(zz{y,z,0});
v[y].push_back(zz{x,z,0});
}
Dijkstra(st,ed);
return 0;
}