白駿1461、図書館-Greedy



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

1.アイデア

  • すべての本を元の場所に戻した後、再び原点0に戻る必要X
    =>最も遠い距離のm本書を最後に電源を切る必要があります
  • 1)本ごとの位置リストを距離が遠い(節価が大きい)順に並べ替える
  • 負の値のリスト、正の値のリストはそれぞれ格納して並べ替えます
    =>原点(負数、正数)の本に対してそれぞれ往復します.
    e.g.一度に取れる本は2冊、残りの本は-6と2のとき
    => (2 x 6) + (2 x 2)
  • 2)最も距離の遠いm本書は最後に整理して終わり、単純+片道
    3)その後、残りの本は距離が遠い順+往復距離(+2倍距離)
    =>「負座標」リスト、「正座標」リストからそれぞれm個を繰り返し文として選択
    ex)例1
    ①一番遠い-39に行って、2冊の本を整理します(-39,-37)
    => + 39
    ②その後整理(-29,-28)2冊,(-6)1冊,(2,11)2冊
    => + (29 x 2) + (6 x 2) + (11 x 2)

    2.資料構造

  • ArrayList<Integer>2個:負座標、正座標リスト
    =>距離が遠い順(節値が大きい順)に並べ替え
  • 3.時間複雑度

  • 2つのリストソート:略O(2 xn log 2 n)
    =>n最大値代入:2 x 50 log 2 50から=500
  • コード#コード#

    import java.io.*;
    import java.util.*;
    
    public class Main {
    	static int n, m;			// 책의 개수 n, 한 번에 들 수 있는 책 최대 개수 m
    	static List<Integer> plusPosList = new ArrayList<>();
    	static List<Integer> minusPosList = new ArrayList<>();
    	static int maxDistPos;		// 원점으로부터 가장 먼 거리의 위치
    	static int minStep;			// 출력, 최소 걸음 수
    
    	static void solution() {
    		// 거리가 먼 순으로 m개 씩 원점을 왕복하며(거리 x 2) minStep 에 더함
    		while (!plusPosList.isEmpty()) {
    			// 한 번에 최대 m개 책 이동
    			for (int i = 0; i < m; i++) {
    				if (plusPosList.isEmpty())
    					break;
    
    				// 왕복 이동 거리: m개 책 묶음에서, 첫 번째 가장 먼 책의 거리 x 2
    				if (i == 0)
    					minStep += plusPosList.get(0) * 2;
    				plusPosList.remove(0);
    			}
    		}
    
    		while (!minusPosList.isEmpty()) {
    			// 한 번에 최대 m개 책 이동
    			for (int i = 0; i < m; i++) {
    				if (minusPosList.isEmpty())
    					break;
    
    				// 왕복 이동 거리: m개 책 묶음에서, 첫 번째 가장 먼 책의 거리 x 2
    				if (i == 0)
    					minStep += -(minusPosList.get(0)) * 2;
    				minusPosList.remove(0);
    			}
    		}
    
    		// 마지막에 옮기는 가장 먼 책은 왕복 X (위에서 왕복 처리한 거리를 다시 빼줌)
    		minStep -= Math.abs(maxDistPos);
    	}
    
    	public static void main(String[] args) throws IOException {
    		BufferedReader br = new BufferedReader(
    				new InputStreamReader(System.in)
    		);
    		StringTokenizer st = new StringTokenizer(br.readLine());
    
    		n = Integer.parseInt(st.nextToken());
    		m = Integer.parseInt(st.nextToken());
    		st = new StringTokenizer(br.readLine());
    
    		for (int i = 0; i < n; i++) {
    			int pos = Integer.parseInt(st.nextToken());
    
    			if (Math.abs(maxDistPos) < Math.abs(pos))
    				maxDistPos = pos;
    
    			if (pos > 0)
    				plusPosList.add(pos);
    			else
    				minusPosList.add(pos);
    		}
    
    		// 원점으로부터 거리 먼 순(절댓값 큰 순)으로 정렬
    		Collections.sort(plusPosList, Collections.reverseOrder());
    		Collections.sort(minusPosList);
    
    		solution();
    		System.out.println(minStep);
    	}
    }