[LeetCode] 1029.Two City Scheduling
여기를 클릭하면 문제를 볼 수 있습니다.
📕 문제 설명
한 회사가 2n명의 사람을 인터뷰 하고자 한다.
한 사람당 a city로 이동하는 비용을 aCost, b city로 이동하는 비용을 bCost라 하여 이동 비용에 대한 정보가 costs 배열로 주어졌을 때 2n명의 사람을 a city와 b city로 n명씩 이동하게 하되 그 cost의 총합이 최소가 되게 해야 한다.
위의 Example 1을 통해 설명을 추가하자면
4명의 사람이 주어졌기 때문에 a city와 b city에 2명씩 분배되어야 한다. 이때 최소가 되게하는 cost들의 합은
- 1번째 사람을 a city로 (cost = 10)
- 2번째 사람을 a city로 (cost = 10)
- 3번째 사람을 b city로 (cost = 50)
- 4번째 사람을 b city로 (cost = 20)
와 같이 하여 총 합은 10+30+50+20=110 이 최소 cost가 된다.
📕 문제 풀이
만약 문제에 a city 와 b city에 n명씩 분배하라는 조건이 없었으면 각 사람마다 비용이 더 적은 도시로 이동을 시키면 된다.
하지만 이 문제의 경우 n명씩 분배하라는 조건이 있으므로 어느 한 도시로의 이동 비용을 기준으로 잡고 정렬하여 풀면 오류가 발생한다.
예를 들어 cost = [[10,20],[20,30],[30,200],[40,500]]
으로 주어졌다고 하자.
a city로의 이동 비용을 기준으로 정렬하여 풀면 cost의 합이 10+20 (a에 n명이 분배되었으므로 나머지는 b)+200+500=730 이 되므로 최소 비용인 20+30+30+40=120이 나오지 않는다. 그러니 한 도시의 비용을 기준으로 잡고 정렬해서는 풀릴 문제가 아니다.
문제를 다른 방향으로 접근해보자. 위의 예를 다시 생각해보면 비용이 큰 것을 피해서 고르다 보면 최소 cost가 될 것이다. 즉, [40,500],[30,200],[20,30],[10,20]
으로 정렬하여 큰 것을 피해서 고르면 40+30+30+20=120이 되어 최소 cost를 알 수 있다. 그런데 비용이 큰 것은 aCost와 bCost에 모두 존재할 수 있으므로 어느 하나를 기준으로 정렬하는 것이 아니라 둘을 관계지어 정렬해야 한다.
그러므로 |aCost-bCost|
를 계산하여 이 값이 큰 것부터 정렬하여 각 단계마다 적은 것들을 고르다 보면 최소 cost에 도달되어 있을 것이다.
cost = [[30,100],[60,10],[10,50],[100,450]]
이 주어졌다고 하자. |aCost-bCost|
를 기준으로 큰 것부터 정렬을 하면 [100,450],[30,100],[60,10],[10,50]]
이 된다. 여기서 각 단계마다 적은 것을 선택하면 100+30+10+50=190이 되어 최소 cost를 얻을 수 있다.
이제 이것을 코드로 나타내보자.
📕 Code
typedef struct cost
{
int aCost;
int bCost;
} cost; // cost 정보가 담긴 구조체
int compare(cost a, cost b)
{
return abs(a.aCost-a.bCost) > abs(b.aCost-b.bCost);
} // |aCost-bCost| 큰 순으로 정렬
class Solution
{
public:
int twoCitySchedCost(vector<vector<int>>& costs)
{
vector<cost> nCosts;
int len = costs.size();
for(int i=0; i<len; i++)
{
cost tmp;
tmp.aCost = costs[i][0];
tmp.bCost = costs[i][1];
nCosts.push_back(tmp);
}
sort(nCosts.begin(), nCosts.end(), compare);
int ans = 0, an=0, bn=0;
for(int i=0; i<len; i++)
{
if(an == len/2) // a에 n명이 분배 되었다면
{
ans += nCosts[i].bCost; // b city만
bn++;
}
else if(bn == len/2) // b에 n명이 분배되었다면
{
ans += nCosts[i].aCost; // a만
an++;
}
else // 아직 n명씩 덜 분배되었다면
{
if(nCosts[i].aCost < nCosts[i].bCost) // 더 작은 비용의 도시를 선택
{
ans += nCosts[i].aCost;
an++;
}
else
{
ans += nCosts[i].bCost;
bn++;
}
}
}
return ans;
}
};
📕 후기
정렬의 기준을 생각하는 데에 시간이 좀 걸렸다. 정렬 기준을 찾고 나서도 왜 그게 정렬기준이 되는지 정확히 설명하기 어려웠다. 그래도 혼자 힘으로 greedy algorithm 문제를 풀어 기뻤다.
Author And Source
이 문제에 관하여([LeetCode] 1029.Two City Scheduling), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@limequeen/LeetCode-1029.Two-City-Scheduling저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)