반응형

문제 링크

 

10819번: 차이를 최대로

첫째 줄에 N (3 ≤ N ≤ 8)이 주어진다. 둘째 줄에는 배열 A에 들어있는 정수가 주어진다. 배열에 들어있는 정수는 -100보다 크거나 같고, 100보다 작거나 같다.

www.acmicpc.net

 

 

착오 )

  처음에는 그리디하게 접근하려고 했다.

  입력받은 배열을 정렬한 이후 배열의 앞부터 가장 큰 수와 가장 작은 수를 번갈아가면서 저장하려고했지만 이런 방법으로는 안된다는 것을 반례를 통해 알게되어 다른 방법으로 접근했다.

  이 방법을 좀더 개선한다면 그리디로 풀 수 있을 거라고 생각된다.

 

풀이 ) 

  입력받은 배열의 모든 순열에 대해서 결과값을 비교하면서 최댓값을 구했다.

  다음 순열에 대해서는 nextPermutation( ) 메서드를 구현해서 사용했다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[] arr = new int[n];
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        for(int i = 0; i < n; ++i)
            arr[i] = Integer.parseInt(st.nextToken());

        Arrays.sort(arr);
        int ans = -(int)1e7;
        do{
            ans = Math.max(ans, cal(arr));
        } while(nextPermutation(arr));
        System.out.println(ans);
    }

    static boolean nextPermutation(int[] arr) {
        int len = arr.length;
        int i=len-1;
        while( i>0 && arr[i-1] >= arr[i] )
            --i;
        if(i==0)
            return false;

        int j = len-1;
        while(arr[i-1]>=arr[j])
            --j;

        int tmp = arr[i-1];
        arr[i-1] = arr[j];
        arr[j] = tmp;

        int k = len-1;
        while(i<k) {
            tmp=arr[i];
            arr[i++]=arr[k];
            arr[k--]=tmp;
        }
        return true;
    }

    static int cal(int[] arr){
        int len = arr.length;
        int ret = 0;
        for(int i = 1; i < len; ++i)
            ret += Math.abs(arr[i]-arr[i-1]);
        return ret;
    }
}
반응형
반응형

문제 링크

 

17142번: 연구소 3

인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고

www.acmicpc.net

 

 

풀이 )

  처음에는 방문 여부를 나타내는 boolean 2차원 배열 visited를 선언하지 않고 풀려다가 많은 문제가 발생했다.

  • 비활성화된 바이러스를 0으로 갱신하고 시작
    • 처음에 다 퍼져있는 경우에 대해서 다른 결과를 출력한다.
  • 바이러스가 방문한 곳을 2로 갱신하고, 1이 아닌 곳만 방문
    • 큐에 중복 방문으로 인한 메모리 초과
  • 바이러스가 방문한 곳을 3으로 갱신하고, 0 2인 곳만 방문
    • 비활성화된 바이러스를 벽으로 생각함

 

  결국 visited 배열을 사용해서 했다.

 

  자세한 풀이는 아래 주석을 달아두었다.

import java.awt.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int[] dx = {0, 1, 0, -1};
    static int[] dy = {1, 0, -1, 0};

    static int n,m;
    static int[][] board;
    static int ans = (int)1e7;
    static ArrayList<Point> virusList = new ArrayList<>();

    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());
        board = new int[n][n];
        for(int i = 0; i < n; ++i){
            st = new StringTokenizer(br.readLine(), " ");
            for(int j = 0; j < n; ++j){
                board[i][j] = Integer.parseInt(st.nextToken());
                if(board[i][j] == 2){
                    virusList.add(new Point(i, j));
                }
            }
        }
        // 입력 & 비활성화된 바이러스를 list에 저장

        combination(m, new int[m], 0);	// 활성화될 바이러스 선택(조합 - virusList.size() C m)
        if(ans == (int)1e7)
            ans = -1;
        System.out.println(ans);
    }

    static void combination(int toPick, int[] picked, int pos){
        if(toPick == 0){
            bfs(picked);	// 활성화될 바이러스를 시작으로 bfs 탐색
            return;
        }

        for(int i = pos; i < virusList.size(); ++i){
            picked[picked.length-toPick] = i;
            combination(toPick-1, picked, i+1);
        }
    }

    static void bfs(int[] picked){
        int[][] tmp = new int[n][];
        for(int i = 0; i < n; ++i)
            tmp[i] = board[i].clone();	// board 값에 영향을 주지 않기 위한 임시 배열
        boolean[][] visited = new boolean[n][n];	// 방문 여부

        Queue<Point> virusQ = new LinkedList<>();
        for(int i = 0; i < picked.length; ++i){
            Point virus = virusList.get(picked[i]);
            virusQ.offer(virus);
            visited[virus.x][virus.y] = true;
        }	// 활성화될 바이러스를 큐에 집어 넣으면서 방문여부 갱신

        int time = -1;	// 바이러스가 퍼지는데 걸리는 시간
        while(!virusQ.isEmpty()){
            time++;
            boolean flag = false;	// 바이러스가 퍼졌는지 확인할 때 2중 for문을 탈출하기 위한 flag
            for(int i = 0; i < n; ++i){
                for(int j = 0; j < n; ++j)
                    if(tmp[i][j] == 0){
                        flag = true;
                        break;
                    }
                if(flag)
                    break;
            }
            if(!flag){	// 바이러스가 더이상 퍼질 수 없으면 ans를 갱신하고 종료
                ans = Math.min(ans, time);
                return;
            }

            int size = virusQ.size();
            while(size-- > 0){
                Point cur = virusQ.poll();
                int x = cur.x, y = cur.y;
                for(int dir = 0; dir < 4; ++dir){
                    int nx = x+dx[dir], ny = y+dy[dir];
                    if(!isIn(nx, ny) || tmp[nx][ny] == 1 || visited[nx][ny])	// 확산할 수 없는 경우
                        continue;
                    visited[nx][ny] = true;	// 확산할 수 있는 경우 방문 여부와 임시 배열을 갱신하고, 큐에 추가
                    tmp[nx][ny] = 2;
                    virusQ.offer(new Point(nx, ny));
                }
            }
            if(virusQ.isEmpty())
                break;
        }
    }

    static boolean isIn(int x, int y){
        return 0 <= x && x < n && 0 <= y && y < n;
    }
}

 

주의 )

  처음 ans의 값을 100으로 설정해서 틀렸다.

  초기에 주어진 바이러스가 1개이고 가로세로 50의 ㄹ모양의 연구소가 주어지면 100초 이상 걸리기 때문에 넉넉한 값을 주어야 한다.

반응형
반응형

문제 링크

 

2116번: 주사위 쌓기

첫줄에는 주사위의 개수가 입력된다. 그 다음 줄부터는 한 줄에 하나씩 주사위의 종류가 1번 주사위부터 주사위 번호 순서대로 입력된다. 주사위의 종류는 각 면에 적혀진 숫자가 그림1에 있는

www.acmicpc.net

 

 

풀이 )

  가장 먼저 주사위의 마주보는 면을 짝 지어주기 위해 (0, 3), (1, 4), (2, 5) 인덱스에 각각 마주보는 면을 저장해주었다.

 

  가장 바닥에 올 수 있는 면은 1번 주사위의 면 6개 중 하나이기 때문에 전체 6가지 답이 나올 수 있다.

  각 주사위에 대해서 밑면의 숫자를 bottom, 윗면의 숫자를 top이라고 하면 이때 가장 큰 답이 나오기 위해서는 위, 아랫면을 제외한 4면 중 가장 큰 값을 선택하면 된다.

  이 값을 구하기 위한 getSide( )메서드에서는

  • bottom과 top이 각각 5와 6 또는 6과 5인 경우 (즉, 합이 13) 4를 반환
  • bottom 또는 top이 6이고 나머지는 5 미만인 경우 5를 반환
  • 그 이외의 경우에는 6을 반환한다.

 

  이전 주사위의 윗면의 숫자와 일치하는 현재 주사위의 아랫면과 현재 주사위의 윗면을 제외한

  나머지 현재 주사위의 옆면에 대해서도 같은 작업을 반복한다.

 

  이렇게 구한 값 중 최댓값이 답이 된다.

 

(마주보는 면의 인덱스를 조건문 처리해주지 않기 위해 i와 (i+3)%6으로 구했다.)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] in;

        int n = Integer.parseInt(br.readLine());
        int[][] dice = new int[n][6];
        for(int i = 0; i < n; ++i){
            in = br.readLine().split(" ");
            dice[i][0] = Integer.parseInt(in[0]);
            dice[i][1] = Integer.parseInt(in[1]);
            dice[i][2] = Integer.parseInt(in[2]);
            dice[i][3] = Integer.parseInt(in[5]);
            dice[i][4] = Integer.parseInt(in[3]);
            dice[i][5] = Integer.parseInt(in[4]);
        }

        int max = 0;
        for(int i = 0; i < 6; ++i){
            int bottom = dice[0][i];
            int top = dice[0][(i+3)%6];
            int sum = getSide(bottom, top);
            for(int j = 1; j < n; ++j){
                for(int k = 0; k < 6; ++k){
                    if(dice[j][k] == top){
                        bottom = dice[j][k];
                        top = dice[j][(k+3)%6];
                        break;
                    }
                }
                sum += getSide(bottom, top);
            }
            max = Math.max(max, sum);
        }
        System.out.println(max);
    }

    public static int getSide(int bottom, int top){
        if(bottom+top == 11)
            return 4;
        else if(bottom == 6 || top == 6)
            return 5;
        else
            return 6;
    }
}
반응형
반응형

문제 링크

 

15686번: 치킨 배달

크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸

www.acmicpc.net

 

 

풀이 )

  입력으로 받은 집과 치킨집을 각각 home, chic vector에 넣어줬다.

  풀고나서 보니 city는 한번도 안썼다.

 

  이후 길이가 chic vector에서 1개를 시작으로 m개까지의 조합을 만들어 선택된 치킨집을 이용해 sum( )을 호출하여 치킨 거리를 계산한다.

 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int n, m;
vector<pair<int, int> > chic;
vector<pair<int, int> > home;

int calc(pair<int, int> chic, pair<int, int> home){
    return abs(chic.first-home.first)+abs(chic.second-home.second);
}

int sum(vector<int> picked){
    int hLen = home.size();
    int pLen = picked.size();
    int ret = 0;

    for(int i = 0; i < hLen; ++i){
        int tmp = 1e9;
        for(int j = 0; j < pLen; ++j)
            tmp = min(tmp, calc(home[i], chic[picked[j]]));
        ret += tmp;
    }

    return ret;
}

int dfs(vector<int> picked, int cLen, int pos, int cnt){
    if(cnt == 0)
        return sum(picked);

    int ret = 1e7;
    for(int i = pos; i < cLen; ++i){
        picked.push_back(i);
        ret = min(ret, dfs(picked, cLen, i+1, cnt-1));
        picked.pop_back();
    }
    return ret;
}

int main(void){
    cin >> n >> m;
    vector<vector<int> > city(n, vector<int>(n));

    for(int i = 0; i < n; ++i){
        for(int j = 0; j < n; ++j){
            cin >> city[i][j];
            if(city[i][j] == 2)
                chic.push_back({i, j});
            if(city[i][j] == 1)
                home.push_back({i, j});
        }
    }

    int cLen = chic.size();
    int ans = 1e7;
    for(int i = 1; i <= m; ++i)
        ans = min(ans, dfs(vector<int>(0), cLen, 0, i));
    cout << ans << '\n';
}

 

반응형
반응형

문제 링크

 

로그인

 

www.acmicpc.net

 

 

풀이 )

  모든 버튼이 망가진 경우 '+'나 '-'로만 조작해야하기 때문에 abs(n-100)을 출력하고 종료한다.

 

  고장난 버튼을 제외한 버튼을 v vector에 넣었다.

  답이 나올 수 있는 경우는 다음 3가지 중 하나다.

  • n의 길이+1인 채널에서 '-'로 n에 도달
  • n의 길이인 채널에서 '-' 또는 '+'로 n에 도달
  • n의 길이-1인 채널에서 '+'로 n에 도달

 

  따라서 v에 들어있는 숫자를 이용해서 각 경우의 길이 숫자를 모두 만들어서 최솟값을 갱신한다.

 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int n, m;
int tmp = 1e7;

int func(vector<int> v, int len, int channel){
    if(len == 0){
        tmp = min(tmp, abs(channel-n));
        return tmp;
    }

    int ret = 1e7;
    int vLen = v.size();
    for(int i = 0; i < vLen; ++i)
        ret = min(ret, func(v, len-1, channel*10+v[i]));
    return ret;
}

int main(void){
    vector<bool> broken(10);
    cin >> n >> m;
    for(int i = 0; i < m; ++i){
        int tmp;
        cin >> tmp;
        broken[tmp] = true;
    }
    int ans = abs(n-100);
    if(m == 10){
        cout << ans << '\n';
        return 0;
    }

    vector<int> v;
    for(int i = 0; i < 10; ++i){
        if(!broken[i])
            v.push_back(i);
    }

    int len = 1;
    int tmp = n;
    while(tmp/=10)
        len++;

    if(len > 1)
        ans = min(ans, func(v, len-1, 0)+len-1);
    ans = min(ans, func(v, len, 0)+len);
    ans = min(ans, func(v, len+1, 0)+len+1);

    cout << ans << '\n';
}

 

주의 )

  출력 전 세 줄에 대해서 len-1, len, len+1 순이 아닌 len+1, len, len-1 순으로 갱신할 경우 원하는 답과 다른 결과가 나온다. (func가 반환하는 값이 버튼을 누른 횟수는 반영하지 않기 때문에)

반응형

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

[C++] 백준 - 11559 : Puyo Puyo  (0) 2021.01.11
[C++] 백준 - 15686 : 치킨 배달  (0) 2021.01.06
[C++] 백준 - 17471 : 게리맨더링  (0) 2020.12.24
[C++] 백준 - 14503 : 로봇 청소기  (0) 2020.12.23
[C++] 백준 - 1719 : 택배  (0) 2020.12.22
반응형

문제 링크

 

algospot.com :: CLOCKSYNC

Synchronizing Clocks 문제 정보 문제 그림과 같이 4 x 4 개의 격자 형태로 배치된 16개의 시계가 있다. 이 시계들은 모두 12시, 3시, 6시, 혹은 9시를 가리키고 있다. 이 시계들이 모두 12시를 가리키도록

algospot.com

 

 

풀이 )

  0번 스위치를 시작으로 15번 스위치까지 각각 4번씩 눌러가면서 재귀호출을 통해서 모든 경우의 수에 대해서 탐색한다.

  전체 경우의 수가 4^10(10^6)이므로 시간초과가 나지 않는다.

 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> push[10] = {
    {0, 1, 2},
    {3, 7, 9, 11},
    {4, 10, 14, 15},
    {0, 4, 5, 6, 7},
    {6, 7, 8, 10, 12},
    {0, 2, 14, 15},
    {3, 14, 15},
    {4, 5, 7, 14, 15},
    {1, 2, 3, 4, 5},
    {3, 4, 5, 9, 13}
};
int clocks[16];

int dfs(int num){
    if(num == 10){
        for(int i = 0; i < 16; ++i){
            if(clocks[i] != 12)
                return 1e7;
        }
        return 0;
    }

    int ret = 1e7;
    for(int i = 0; i < 4; ++i){
        ret = min(ret, i+dfs(num+1));
        int len = push[num].size();
        for(int i = 0; i < len; ++i){
            clocks[push[num][i]] = clocks[push[num][i]]%12+3;
        }
    }
    return ret;
}

int main(void){
    int c;
    cin >> c;
    while(c--){
        for(int i = 0; i < 16; ++i)
            cin >> clocks[i];

            int ans = dfs(0);
            if(ans >= 1e7)
                ans = -1;
            cout << ans << '\n';
    }
}
반응형

'문제풀이 > 알고스팟' 카테고리의 다른 글

[C++] 알고스팟 - BOARDCOVER  (0) 2020.12.28
[C++] 알고스팟 - PICNIC  (0) 2020.11.01
[C++] 알고스팟 - FESTIVAL  (0) 2020.03.09

+ Recent posts