ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 2180 (소방서의 고민) c++
    백준 문제 2022. 2. 5. 18:25
    728x90

    문제

     

    2180번: 소방서의 고민

    첫째 줄에 화재 발생 건수 n이 주어진다. n은 200,000 이하의 양의 정수이다. 둘째 줄부터 n개의 줄에 각각 한 줄에 한 쌍씩 a와 b가 입력된다. a와 b는 40,000 이하의 음이 아닌 정수이다.

    www.acmicpc.net

    n개의 화재가 발생하고 소방수가 최소의 시간으로 화재를 진압하는 시간을 구하는 문제입니다.

    화재를 진압하는 시간은 a * t + b로 n개의 a, b가 주어지고 t는 항상 0부터 시작합니다.

    예를 들어 n이 3이고 a, b가 (2, 0), (1, 2), (0, 3) 이렇게 주어지면 최소시간은 5 입니다.

    (2 * t0 + 0) + (1 * t1 + 2) + (0 * t2 + 3)

    =5 

     

    우리는 화재를 최대한 빠르게 진압해야 하므로 어느 조건으로 화재를 진압해야 빨리 화재가 진압되는지

    알아 내야 합니다.

    즉 최적해를 구해야 합니다.

    예를 들어 다음과 같은 n개의 화재가 있다고 하면 t(i+2)를 구하는 방법을 보겠습니다.

    t(i+2) = t(i) + a(i)*t(i) + b(i) + a(i+1)*(t(i) + a(i)*t(i) + b(i)) + b(i+1) 입니다.

     

    반대로 최적해가 아닌 경우 즉, 아무렇게나 화재를 진압할 경우를 보겠습니다.

    t(i+2)' =t(i) + a(i+1)*t(i) + b(i+1) + a(i)*(t(i) + a(i+1)*t(i) + b(i+1)) + b(i) 입니다.

     

    결로부터 보자면 t(i+2)는 항상 t(i+2)' 보다 작거나 같아야 합니다. 왜냐하면 t(i+2)이 t(i+1)' 보다 커져버리면 

    결국 시간이 계속 축적되어 마지막에 시간이 더 오래걸린채로 남아있기 때문입니다.

    결국 시간은 계속 흐르기 때문에 앞에서 최소한의 시간을 할애 해야 마지막에 시간이 최소가 됩니다. 

    따라서 t(i+2) <= t(i+2)' 이기 때문에 식을 간소화 하면

    t(i) + a(i)*t(i) + b(i) + a(i+1)*(t(i) + a(i)*t(i) + b(i)) + b(i+1)

    ≤ t(i) + a(i+1)*t(i) + b(i+1) + a(i)*(t(i) + a(i+1)*t(i) + b(i+1)) + b(i)

    중복된 식을 다 제거하면

    b(i)*a(i+1) ≤ b(i+1)*a(i) 입니다.

    식을 좀더 간소화 하면 다음과 같습니다.

    하지만 이러한 식은 a가 0일 때는 불가능한 식입니다.

    a가 0일 때는 항상 b만큼의 시간이 걸립니다. 

    따라서 a = 0일 때는 어느 차례에서나 항상 시간이 b값이 되므로 맨 마지막에 불을 꺼도 상관이 없습니다.

    결국에는 a가 0일 때는 제외하고 위의 식이 성립하게 됩니다.

     

    즉, a를 계속 보다가 0이 나오면 그냥 맨 뒤로 보내줍니다.

    또한 만약 a의 어느 구간이

    이러면 두 수의 위치를 서로 바꿔주면 최적해와 유사하게 진행됩니다.

     

    따라서 우리는 먼저 a와 b를 입력받은 배열을 알맞은 조건에 맞게 정렬해주어야 합니다.

    bool cmm(pair<int,int> a, pair<int,int> b) {
    	if (a.first == 0)return false;
    	else if (b.first == 0)return true;
    	else if (a.second == 0 && b.second == 0)return a.first < b.first;
    	return a.second * b.first < a.first* b.second;
    }

    정렬 함수입니다.

    int time = 0;
    	for (int i = 0; i < v.size(); i++) {
    		time = time+time * v[i].first + v[i].second;
    		time %= 40000;
    	}

    시간을 계산하는 코드입니다.


    전체 코드입니다.

    #include<iostream>
    #include<algorithm>
    #include<climits>
    #include<string>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<cmath>
    #include<time.h>
    #include<cstring>
    #include<cmath>
    #include<cstring>
    #include<limits>
    #define inf INT_MAX
    using namespace std;
    using ll = long long;
    using ull = unsigned long long;
    bool cmm(pair<int, int> a, pair<int, int> b);
    vector<pair<int, int>>v;
    int main() {
    	ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
    	int n;
    	cin >> n;
    	for (int i = 0,a,b; i < n; i++) {
    		cin >> a >> b;
    		v.push_back({ a,b });
    	}
    	sort(v.begin(), v.end(), cmm);
    	int time = 0;
    	for (int i = 0; i < v.size(); i++) {
    		time = time+time * v[i].first + v[i].second;
    		time %= 40000;
    	}
    	cout << time;
    	return 0;
    }
    bool cmm(pair<int,int> a, pair<int,int> b) {
    	if (a.first == 0)return false;
    	else if (b.first == 0)return true;
    	else if (a.second == 0 && b.second == 0)return a.first < b.first;
    	return a.second * b.first < a.first* b.second;
    }

    '백준 문제' 카테고리의 다른 글

    백준 11280 (2-SAT _3) C++  (0) 2022.02.09
    백준 2150 (Strongly Connected Component) c++  (0) 2022.02.09
    백준 1931 (회의실 배정) c++  (0) 2022.02.04
    백준 1761번 (정점들의 거리) c++  (0) 2022.02.04
    백준 11438번 (LCA 2) C++  (0) 2022.02.04
Designed by Tistory.