2763: [JLOI2011]飞行路线
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 3203 Solved: 1223
[Submit][Status][Discuss]Description
Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?Input
数据的第一行有三个整数,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)Output
只有一行,包含一个整数,为最少花费。Sample Input
5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100
Sample Output
8HINT
对于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.
题意
给出一个无向图, 求从指定结点到达另一个指定结点的最短路, 其中有 $k$ 次机会可以忽视某一条边的长度.
题解
看起来像是普通的最短路, 但是 $k$ 次免费机会给了这个最短路不少不确定因素. 但是我们不难得出结论: 只要最短路上的边数多于 $k$ , 最优解一定使用了 $k$ 次免费机会. 所以我们可以使用二维最短路来解决这个问题, 与一维最短路非常相似, 不同的是在维护最短路的时候要多维护一个如果使用一次免费机会则可以得到的最短路值.
参考代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <queue> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <iostream> 6 #include <algorithm> 7 8 const int MAXV=10010; 9 const int MAXE=100010; 10 const int MAXK=15; 11 12 struct Edge{ 13 int from; 14 int to; 15 int dis; 16 Edge* next; 17 }; 18 Edge E[MAXE]; 19 Edge* head[MAXV]; 20 Edge* top=E; 21 22 int v; 23 int e; 24 int k; 25 int s; 26 int t; 27 int dis[MAXV][MAXK]; 28 bool visited[MAXV][MAXK]; 29 30 std::deque< std::pair<int,int> > q; 31 32 void SPFA(int); 33 void Initialize(); 34 void FastRead(int&); 35 void Insert(int,int,int); 36 37 int main(){ 38 Initialize(); 39 SPFA(s); 40 printf("%d ",dis[t][k]); 41 return 0; 42 } 43 44 void SPFA(int s){ 45 int used; 46 memset(dis,0x3F,sizeof(dis)); 47 dis[s][0]=0; 48 visited[s][0]=true; 49 q.push_front(std::make_pair(s,0)); 50 while(!q.empty()){ 51 std::pair<int,int> p=q.front(); 52 q.pop_front(); 53 s=p.first; 54 used=p.second; 55 visited[s][used]=false; 56 for(Edge* i=head[s];i!=NULL;i=i->next){ 57 if(dis[i->to][used]>dis[s][used]+i->dis){ 58 dis[i->to][used]=dis[s][used]+i->dis; 59 if(!visited[i->to][used]){ 60 visited[i->to][used]=true; 61 if(!q.empty()&&dis[i->to][used]<dis[q.front().first][q.front().second]) 62 q.push_front(std::make_pair(i->to,used)); 63 else 64 q.push_back(std::make_pair(i->to,used)); 65 } 66 } 67 if(used<k&&dis[i->to][used+1]>dis[s][used]){ 68 dis[i->to][used+1]=dis[s][used]; 69 if(!visited[i->to][used+1]){ 70 visited[i->to][used+1]=true; 71 if(!q.empty()&&dis[i->to][used]<dis[q.front().first][q.front().second]) 72 q.push_front(std::make_pair(i->to,used+1)); 73 else 74 q.push_back(std::make_pair(i->to,used+1)); 75 } 76 } 77 } 78 } 79 } 80 81 void Initialize(){ 82 int a,b,c; 83 FastRead(v); 84 FastRead(e); 85 FastRead(k); 86 FastRead(s); 87 FastRead(t); 88 for(int i=0;i<e;i++){ 89 scanf("%d%d%d",&a,&b,&c); 90 Insert(a,b,c); 91 Insert(b,a,c); 92 } 93 } 94 95 inline void Insert(int from,int to,int dis){ 96 top->to=to; 97 top->dis=dis; 98 top->from=from; 99 top->next=head[from]; 100 head[from]=top; 101 top++; 102 } 103 104 inline void FastRead(int& target){ 105 target=0; 106 register char ch=getchar(); 107 while(!isdigit(ch)) 108 ch=getchar(); 109 while(isdigit(ch)){ 110 target=target*10+ch-'0'; 111 ch=getchar(); 112 } 113 }