[伯俊]1781杯ラーメン


白俊1781カップカップラーメン
  • https://www.acmicpc.net/problem/1781
  • エラーの回答

  • 作業は迅速に選別する順序で並べ替えられ、作業の選別順序が同じであれば、得られるカップ麺は複数の順序で並べ替えられる.
    ->高速作業を完了することから、その作業を完了する前提でできるだけ多くの作業を完了するグリディアルゴリズムを設計した.

  • 反例(https://www.acmicpc.net/board/view/6365)
    input:
    9
    5 5
    4 6
    4 12
    3 8
    4 18
    2 10
    2 5
    1 7
    1 14
    output: 55
    answer: 65

  • 私が実施したGRADYアルゴリズム:
    ジョブソート:(1,14)、(1,7)、(2,10)、(2,5)、(3,8)、(4,18)、(4,12)、(4,6)、(5,5)
    現在時刻0からDedrain 1:(1,14)を選択
    現在時刻1からDedrain 2:(2,10)を選択
    現在時刻2~選択Dedrain 3:(3,8)
    現在時刻3からDedrain 4:(4,18)を選択
    現在の時刻4~5を選択します.(5,5)
    ->得られるカップ麺の総数:14+10+8+18+5=55

  • 答え:
    (1、14)、(2、10)、(4、18)、(4、12)、(5、5)選択
    ->合計のカップラーメン数:14+10+18+5=59
    ->分機ジョブごとに1つを選択する必要はありません
  • #include <iostream>
    #include <queue>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    int n;
    int cnt = 0;
    
    //<숙제 데드라인, 얻게되는 컵라면 수>
    vector<pair<int, int>> hw;
    
    //데드라인 빠른 순서대로 정렬
    //데드라인 같다면 컵라면 수 많은 순서대로 정렬
    bool cmp(const pair<int, int>& a, const pair<int, int>& b) {
    	if (a.first < b.first) return true;
    	if (a.first == b.first) return a.second > b.second;
    	return false;
    }
    
    //lower_bound를 위한 pair 비교 함수
    bool paircmp(const pair<int, int>& a, const pair<int, int>& b) {
    	return a.first < b.first;
    }
    
    int main() {
    	ios_base::sync_with_stdio(false);
    	cin.tie(NULL);
    	cout.tie(NULL);
    
    	cin >> n;
    	for (int i = 0; i < n; ++i) {
    		int deadline, cup;
    		cin >> deadline >> cup;
    		hw.push_back(make_pair(deadline, cup));
    	}
    	//숙제 정렬
    	sort(hw.begin(), hw.end(), cmp);
    
    	//현재 시간
    	int curtime = 0;
    	//현재 할 수 있는 숙제의 인덱스
    	int index = 0;
    	while (index < n) {
    
    		int deadline = hw[index].first;
    		
    		//현재 데드라인 내에서 할 수 있는 숙제의 개수만큼 숙제를 한다
    		int num_of_hw = deadline - curtime;
    		for (int i = 0; i < num_of_hw; ++i) {
    			if (index == n) break;
    
    			cnt += hw[index].second;
    			index++;
    		}
    
    		curtime = deadline;
    		//현재 데드라인 이후 할 수 있는 숙제의 인덱스
    		int next_index = upper_bound(hw.begin(), hw.end(), make_pair(deadline, 0), paircmp) - hw.begin();
    		index = next_index;
    	}
    
    	cout << cnt;
    	return 0;
    }
    のり

  • 現在時刻1:Dedrain 1人作業~Dedrain Nが選択できる作業の一つ
    現在時刻2:2人分~1人分を選択可能
    ...
    現在時刻N-1:デッドラインN-1付きジョブ~デッドライン付きジョブを選択可能
    今時間N:宿題を選ぶことができます.

  • 現在の時間をmaxheapに逆順序で追加
    ->現在時刻選択可能なデータソースを持つジョブをmaxheapに格納する

  • 現在時刻N:maxheapにデータウェアハウス用のジョブを追加
    ->データウェアハウスNであるmaxheapにジョブを保存しました
    ->カップラーメンの最大数を選ぶ作業
    現在時刻N-1:maxheapにDedrain N-1というジョブを追加
    ->ジョブをmaxheapに保存し、ジョブは分機N-1、ジョブは分機
    ->カップラーメンの最大数を選ぶ作業
    ...
    現在時刻1:ジョブを1人追加
    ->maxheapにジョブを保存しました.ジョブは1、ジョブは1、ジョブはN
    ->カップラーメンの最大数を選ぶ作業
  • #include <iostream>
    #include <vector>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    typedef unsigned long long ull;
    
    int N;
    //<숙제 데드라인, 숙제 컵라면>
    vector<pair<int, int>> hw;
    
    //총 얻을 수 있는 컵라면의 수
    ull cnt = 0;
    priority_queue<int> maxheap;
    
    int main() {
    	ios_base::sync_with_stdio(false);
    	cin.tie(NULL);
    	cout.tie(NULL);
    
    	cin >> N;
    
    	for (int i = 0; i < N; ++i) {
    		int a, b;
    		cin >> a >> b;
    		hw.push_back(make_pair(a, b));
    	}
    
    	sort(hw.begin(), hw.end());
    
    	//현재 시각 N부터 1까지 역순으로 생각한다
    	for (int cur = N; cur > 0; --cur) {
    
    		//hw 데드라인 오름차순으로 정렬됨 -> 역방향으로 순회
    		for (int i = hw.size()-1; i >= 0; --i) {
    
    			//현재 시각이 deadline인 hw의 컵라면 수 maxheap에 추가
    			if (hw[i].first == cur) {
    				maxheap.push(hw[i].second);
    				hw.pop_back();
    			}
    			else break;
    		}
    		
            	//컵라면 수 가장 큰 숙제 선택
    		if (!maxheap.empty()) {
    			cnt += maxheap.top();
    			maxheap.pop();
    		}
    	}
    	
    	cout << cnt;
    	return 0;
    }