ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준 10043] 택시
    C 프로그래밍/BOJ 2022. 9. 19. 23:49
    728x90

    https://www.acmicpc.net/problem/10043

     

    10043번: タクシー (Taxis)

    IOI 国は町 1 から町 N までの N 個の町からなり,町と町とは道路で結ばれている.IOI 国には K 本の道路があり,すべての道路は異なる 2 つの町を結んでいる.車は道路を双方向に自由に移動

    www.acmicpc.net

    // BFS로 해결 
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #include <list>	
    int N, K;
    int chk[5000 + 2][5000 + 2];	// 상태발전을 위한 체크배열
    
    struct _st
    {
    	int n;
    	int cnt;
    	int cost;
    };
    
    
    struct _tx
    {
    	int cost;
    	int cnt;
    }taxi[5000 + 2];
    
    using namespace std;
    
    list<int> adj[5000 + 2];		// 연결된 마을 인접리스트로 표현
    
    
    struct COMP
    {
    	bool operator() (_st &a, _st &b)
    	{
    		return a.cost > b.cost;		// cost를 기준으로 내림차순 정렬한다.	// 그래야 cost 작은 것 부터 나옴 
    	}
    
    };
    priority_queue<_st, vector<_st>, COMP> PQ;	// 최소 비용 구하기 위해
    
    void input(void)
    {
    	scanf("%d %d", &N, &K);
    	for (int i = 1; i <= N; i++) {
    		scanf("%d %d", &taxi[i].cost, &taxi[i].cnt);
    	}
    	for (int i = 0; i < K; i++) {
    		int u = 0; int v = 0;
    		scanf("%d %d", &u, &v);
    		adj[u].push_back(v);
    		adj[v].push_back(u);
    	}
    }
    
    
    
    int BFS(void)
    {
    	fill(&chk[0][0], &chk[0][0] + sizeof(chk) / sizeof(int), 0x7fffffff);	// 방문배열 초기화 
    
    	PQ.push({ 1, 0, 0 });	// 1번 회사에서 이동 횟수가 0번 남은 택시를 탐, 총비용 0원
    	chk[1][0] = 0;			// [회사][남은 이동 횟수] = 총비용 
    
    	while (!PQ.empty()) {
    		_st data = PQ.top();
    		PQ.pop();
    
    		if (data.n == N) return data.cost;
    
    
    		int next = 0; int ncnt = 0; int ncost = 0;
    		if (data.cnt != 0) {	// 이동 횟수가 남아있다면
    			ncnt = data.cnt - 1;	// 이동횟수 차감 
    			ncost = data.cost;		// 안갈아탐		// 비용증가없음 
    
    			for (int nn : adj[data.n]) {
    				next = nn;
    				if (chk[next][ncnt] <= ncost) continue;
    				chk[next][ncnt] = ncost;
    				PQ.push({ next, ncnt, ncost });
    			}
    		}
    
    		ncnt = taxi[data.n].cnt - 1;
    		ncost = data.cost + taxi[data.n].cost;	// data.n번째에서 택시 갈아타니까
    		for (int nn : adj[data.n]) {
    			next = nn;
    			if (chk[next][ncnt] <= ncost) continue;
    			chk[next][ncnt] = ncost;
    			PQ.push({ next, ncnt, ncost });
    		}
    	}
    }
    
    
    int main()
    {
    	input();
    	int ans = BFS();
    	printf("%d\n", ans);
    	return 0;
    }

    ㅇ... 일본어.... 고멘나사이... 

     

    문제 설명을 대충하자면, 1번 노드에서부터 N번 노드까지 가기 위해 필요한 최소 비용을 구하는 문제이다. 

    각 노드는 K개의 도로로 연결되어 있고, 양방향으로 자유롭게 움직일 수 있다. 

    한편 다음과 같은 조건을 따른다. 

    1. i번 택시 회사의 택시는 i번 마을에서만 승차할 수 있다. 

    2. i번 택시 회사의 택시 요금은 이용한 거리에 관계없이 Ci이다.

    3. i번 택시 회사의 택시는 승차 후 연속 최대 Ri개의 도로밖에 갈 수 없다. 

     

     

    // input( ) 함수 

    각 택시의 요금와 이동할 수 있는 도로 수를 구조체에 받아주었고, 연결된 두 노드를 표시하기 위해 리스트를 만들어 놓았다. 또한 양방향으로 자유롭게 이동할 수 있기 때문에 u에도 v를, v에도 u를 추가하였다. 

     

     

    // BFS( ) 함수

    노드 N에 도달했을 때 최소 비용을 리턴하기 위해 "우선순위 큐"를 선언하였다. 

    가장 처음 큐에 담아준 데이터는 1번 노드에서 이동 횟수가 0번 남은 택시를 탔고, 총 비용이 0원인 상태이다. 

    그리고 행번호가 노드, 열번호가 이동횟수인 chk배열의 chk[1][0]에 1번 노드까지 오는데 이동횟수가 0번 남았을 때의 총비용인 0을 대입해준다. 

     

    이후 PQ에서 데이터를 하나씩 꺼내어 상태를 발전시키는데, 만약 꺼낸 데이터의 노드가 N이라면 그때까지의 총 비용(data.sum)을 리턴해주고 종료한다. 

    그게 아니라면 루프를 계속 진행하는데,

    (1) 만약 이동횟수가 아직 남아있다면( if (data.cnt != 0)) 이동 횟수를 차감한다(ncnt = data.cnt - 1). 한편 택시를 갈아타지 않았 기 때문에 비용이 증가하지는 않는다. 따라서 총 비용은 그대로이다(nsum = data.sum).

    (2) 반면 이동횟수가 더이상 남아있지 않다면, 해당 노드에서 새로운 택시로 갈아타고 이동해야 한다. 따라서 새로운 택시를 타야하고, 다음 노드로 이동할 것이므로 이동횟수 -1 을 해준다(ncnt = taxi[data.n].cnt - 1). 또한 총 비용은 지금까지의 금액에 새로운 택시를 탔을 때 발생하는 비용을 더해주어야 한다. (ncost = data.cost + taxi[data.n].cost)   

     

    상기 두 경우 chk배열에서 해당 노드(next)에서 이동횟수가 ncnt개 남았을 때 발생하였던 비용과 새로 계산한 ncost를 비교하여, 새로 계산한 비용이 더 작을 때만 chk 배열을 갱신 후 정보를 우선순위 큐에 삽입한다. 

    728x90

    'C 프로그래밍 > BOJ' 카테고리의 다른 글

    [백준 14867] 물통  (0) 2022.09.20
    [백준 14502] 연구소  (0) 2022.09.20
    [C++ STL] MAP  (0) 2022.09.19
    [C++ STL] SET  (2) 2022.09.19
    [백준 2636] 치즈  (0) 2022.09.18

    댓글

Designed by Tistory.