[BZOJ 2763][JLOI 2011] 飛行路線
阿新 • • 發佈:2017-08-10
can printf getchar http isdigit splay page 是我 front
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$ 次免費機會. 所以我們可以使用二維最短路來解決這個問題, 與一維最短路非常相似, 不同的是在維護最短路的時候要多維護一個如果使用一次免費機會則可以得到的最短路值.
參考代碼
GitHub
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\n",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 }Backup
[BZOJ 2763][JLOI 2011] 飛行路線