http://jungol.co.kr/bbs/board.php?bo_table=pbank&wr_id=2267&sca=60&s1=&s2=&s3=&s4=
경로를 진행할 때 지금 까지 거쳐온 주유소 중 최소 가격으로 계속 주유하면서 가는 것이 최선이다.
dp[i][j]를 현재 i(1<=i<=n)번째 노드에 있을 때, 지나온 경로 중 j번째의 주유소 가격이 최소일 때의 최소 비용이라 정의한다.
이후 i번째에서 갈수 있는 다른 노드로 뻗어가면서 dp테이블을 완성하면 된다.
i번째 노드에서 k번째 노드로 갈 때.
이동 거리를 D라 하자
cost[i]는 i번째 노드의 주유소 값이라 하자.
if(cost[k]>cost[i]){
dp[k][j]=min(dp[k][j],dp[i][j]+D*cost[j]);
else
dp[k][k]=min(dp[k][k],dp[i][j]+D*cost[j]);
이 과정을 힙을 이용해서 시간제한 안에 해결한다.
priroriy queue를 최소가 우선 순위가 되도록 짠다.
처음 모든 dp 배열을 무한대로 초기화한다.
이후 dp[1][1]=0 에서 시작.
priority_queue에 dp,i,j를 dp값이 첫번째 원소가 되도록 넣어 준다.
반복문을 돌리면서 priority_queue top에서 최소 dp 값을 뽑아서 다른 dp 테이블을 갱신 해주고 prioriy_queue에 넣어주면 된다.
dp[N][i](1<=i<=N) 중 최소가 정답이다.
O(NM+N^2 log N)
주유소 풀이
비슷한 문제 유형으로는
Prob No.05C6 : 목초지 최소 이동 시간 [CH03.4.USACO(Gold)]
http://koistudy.net/?mid=prob_page&NO=1478 가 있다. 추후 업데이트 예정
dp[i][j]를 현재 i(1<=i<=n)번째 노드에 있을 때, 지나온 경로 중 j번째의 주유소 가격이 최소일 때의 최소 비용이라 정의한다.
이후 i번째에서 갈수 있는 다른 노드로 뻗어가면서 dp테이블을 완성하면 된다.
i번째 노드에서 k번째 노드로 갈 때.
이동 거리를 D라 하자
cost[i]는 i번째 노드의 주유소 값이라 하자.
if(cost[k]>cost[i]){
dp[k][j]=min(dp[k][j],dp[i][j]+D*cost[j]);
else
dp[k][k]=min(dp[k][k],dp[i][j]+D*cost[j]);
이 과정을 힙을 이용해서 시간제한 안에 해결한다.
priroriy queue를 최소가 우선 순위가 되도록 짠다.
처음 모든 dp 배열을 무한대로 초기화한다.
이후 dp[1][1]=0 에서 시작.
priority_queue에 dp,i,j를 dp값이 첫번째 원소가 되도록 넣어 준다.
반복문을 돌리면서 priority_queue top에서 최소 dp 값을 뽑아서 다른 dp 테이블을 갱신 해주고 prioriy_queue에 넣어주면 된다.
dp[N][i](1<=i<=N) 중 최소가 정답이다.
O(NM+N^2 log N)
주유소 풀이
#include <bits/stdc++.h>
#define N 2505
#define INF 9876543219876LL
using
namespace
std;
typedef
long
long
ll;
typedef
pair<
int
,pair<
int
,
int
> > pp;
vector<
int
> V[N],C[N];
priority_queue<pp,vector<pp>,greater<pp> > Q;
ll n,m,dp[N][N],val[N];
bool
visit[N][N];
void
input(){
scanf
(
"%lld %lld"
,&n,&m);
ll i,x,y,z,j;
for
(i=1;i<=n;i++){
scanf
(
"%lld"
,&val[i]);
for
(j=1;j<=n;j++)
dp[i][j]=INF;
}
for
(i=1;i<=m;i++){
scanf
(
"%lld %lld %lld"
,&x,&y,&z);
V[x].push_back(y);
V[y].push_back(x);
C[x].push_back(z);
C[y].push_back(z);
}
}
void
process(){
ll from,minv,to,i;
dp[1][1]=0;
Q.push(make_pair(0,make_pair(1,1)));
while
(!Q.empty()){
from=Q.top().second.first;
minv=Q.top().second.second;Q.pop();
if
(visit[from][minv]==1)
continue
;
visit[from][minv]=1;
for
(i=0;i<V[from].size();i++){
to=V[from][i];
if
(dp[to][(val[minv]>val[to])? to:minv]>dp[from][minv]+val[minv]*C[from][i]){
dp[to][(val[minv]>val[to]?to:minv)]=dp[from][minv]+val[minv]*C[from][i];
Q.push(make_pair(dp[to][(val[minv]>val[to]?to:minv)],make_pair(to,(val[minv]>val[to]?to:minv))));
}
}
}
}
void
output(){
ll mn=INF,i;
for
(i=1;i<=n;i++)
mn=min(mn,dp[n][i]);
printf
(
"%lld"
,mn);
}
int
main(){
input();
process();
output();
return
0;
}
비슷한 문제 유형으로는
Prob No.05C6 : 목초지 최소 이동 시간 [CH03.4.USACO(Gold)]
http://koistudy.net/?mid=prob_page&NO=1478 가 있다. 추후 업데이트 예정
댓글 없음:
댓글 쓰기