일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- ArticulationPoint
- Math
- Bridge
- backtracking
- DP
- LIS
- DFS
- FenwickTree
- Floyd
- mergesorttree
- scc
- IndexedTree
- Tree
- LCA
- greedy
- SlidingWindow
- KMP
- BFS
- Union-Find
- ShortestPath
- Dijkstra
- topologicalsort
- Implementation
- TwoPointers
- MST
- Flow
- 2-sat
- Sweeping
- BinarySearch
- Bellman-Ford
- Today
- Total
정리충의 정리노트
[백준] 9323: 무임승차 본문
0. 문제 주소
https://www.acmicpc.net/problem/9323
9323번: 무임승차
문제 상현이는 어떤 기밀 단체의 요원이다. 상현이는 매일 아침 기차를 타고 출근한다. 어느 날 출근을 하던 상현이는 무언가 불합리하다는 것을 알아챘다. 상현이는 매일 요금을 내고 기차를 타지만, 실제로 승무원이 티켓을 확인하는 경우는 드물었기 때문이다. 결국 몇 년에 걸쳐, 상현이는 각 기차마다 어느 정도의 확률로 티켓을 확인받게 되는지에 대한 정보를 모두 작성하는 데 성공했다. 하지만 무임승차 벌금은 일반적으로 실제 요금보다 많기 때문에, 상현이는 모든
www.acmicpc.net
1. 풀이

아래 문장이 굉장히 중요하다.
기차 티켓은 기본 s원에 출발지 A와 도착지 B 사이의 최단거리에 비례하여 1 킬로미터당 p의 요금이 추가된다. 당연히 이 티켓으로는 A와 B 사이를 최단거리로 운행하는 기차만 탈 수 있다.
당연히 인접한 역 사이에서만 티켓을 끊을 수 있을 줄 알았는데, 떨어져 있어도 가능했다.
다시 말해서 edge를 거칠 때마다 기본 요금을 낼 필요가 없다는 것이다.
위의 예시에선 1에서 3으로 가는 티켓을 끊으면, 기본 요금 s는 한 번만 내고, 최단거리인 100에 p를 곱한 값만 더 내주면 된다.
맨 처음엔 edge별로 티켓을 끊을지, 무임승차를 할지에 대해서 비교를 해주고 더 싼 값을 weight로 저장해서 풀었는데 틀렸다. 하긴 그러면 플레5가 아니겠지..
여기저기 참고를 해본 결과 dp 테이블로 dp[node][i] = start에서 node까지 가는 최소 비용(i가 0이면 값 지불, 1이면 무임승차)
그래서 다익스트라 알고리즘을 돌리며 아래와 같이 dp 테이블을 갱신해 주어야 한다.
dp[next][0] = min(dp[next][0], min(dp[curr][0] + next_weight*p*1., dp[curr][1] + next_weight*p*1. + s));
dp[next][1] = min(dp[next][1], min(dp[curr][0], dp[curr][1]) + (y + next_weight*p)*(next_prob/100.0));
2. 풀이 코드
* 유의할 점
#######
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
#include <string>
#define pii pair<int, int>
#define piii pair<int, pii>
#define pid pair<int, double>
#define pdi pair<double, int>
#define MAX 205
#define INF 987654321.0
using namespace std;
int T;
int N, M, S, E, s, p, y;
int u, v, prob, w;
vector<piii> graph[MAX];
double dist[MAX];
double dp[MAX][2]; // 0: paid, 1: free
bool visited[MAX];
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif
scanf("%d", &T);
while(T>0){
T--;
scanf("%d %d %d %d %d %d %d", &N, &M, &S, &E, &s, &p, &y);
for (int i=1;i<=N;i++){
graph[i].clear();
}
fill(dist+1, dist+N+1, INF);
memset(visited, 0, sizeof(visited));
for (int i=1;i<=N;i++){
dp[i][0] = dp[i][1] = INF;
}
for (int i=0;i<M;i++){
scanf("%d %d %d %d", &u, &v, &prob, &w);
graph[u].push_back(piii(v, pii(prob, w)));
graph[v].push_back(piii(u, pii(prob, w)));
}
dp[S][0] = s*1.;
dp[S][1] = 0.;
dist[S] = 0.;
priority_queue<pdi, vector<pdi>, greater<pdi>> PQ;
PQ.push(pdi(dist[S], S));
while(!PQ.empty()){
auto ppp = PQ.top();
PQ.pop();
int curr = ppp.second;
double curr_dist = ppp.first;
if (visited[curr]) continue;
visited[curr] = true;
for (auto pp: graph[curr]){
int next = pp.first;
int next_prob = pp.second.first, next_weight = pp.second.second;
dp[next][0] = min(dp[next][0], min(dp[curr][0] + next_weight*p*1., dp[curr][1] + next_weight*p*1. + s));
dp[next][1] = min(dp[next][1], min(dp[curr][0], dp[curr][1]) + (y + next_weight*p)*(next_prob/100.0));
double final_weight = min(dp[next][0], dp[next][1]);
if (dist[next] > final_weight){
dist[next] = final_weight;
PQ.push(pdi(dist[next], next));
}
}
}
printf("%.2f\n", dist[E]);
}
return 0;
}
'PS > ShortestPath' 카테고리의 다른 글
[백준] 1162: 도로포장 (0) | 2020.03.10 |
---|---|
[백준] 1948: 임계 경로 (수정) (0) | 2020.03.10 |
[백준] 2982: 국왕의 방문 (0) | 2020.03.07 |
[백준] 2211: 네트워크 복구 (0) | 2020.03.07 |
[백준] 9370: 미확인 도착지 (0) | 2020.03.07 |