재미있는 문제라서 들고 왔습니다. 

 

1. 해당 방향으로 쭉 탐색하면서 해당 칸 놓는 돌로 변경.

2.1 만약 끝에 같은 돌이 없다면, 다시 원래대로.

2.2 만약 끝에 같은 돌이 있다면, 그대로 유지

 

dfs를 이용해서 풀었습니다.

t = int(input())
directions = [[0,1],[0,-1], [1,0],[-1,0],[1,1],[-1,-1],[1,-1],[-1,1]]
def dfs(board, y,x, dy, dx, c, n):
    if y < 0 or x < 0 or y >= n or x >= n:
        return True
    if board[y][x] == 0:
        return True
    if board[y][x] == c and board[y][x] != 0:
        return False
        
    tmp = board[y][x]
    board[y][x] = c
    flag = dfs(board, y + dy, x + dx, dy, dx, c, n)
    
    if flag:
        board[y][x] = tmp
        
    return flag
for tt in range(1,t+1):
    n,m = map(int, input().split())
    
    board = [[0 for _ in range(n)] for _ in range(n)]
    board[n//2-1][n//2-1] = 2
    board[n//2][n//2] = 2
    board[n//2-1][n//2] = 1
    board[n//2][n//2-1] = 1
    
    for _ in range(m):
        x,y,c = map(int, input().split())
        y -= 1
        x -= 1
        board[y][x] = c
        
        for dy,dx in directions:
            ny = y+dy
            nx = x+dx
            dfs(board,ny,nx,dy,dx,c,n)
            
    b_cnt = 0
    w_cnt = 0
    
    for i in range(n):
        for j in range(n):
            if board[i][j] == 2:
                w_cnt += 1
            elif board[i][j] == 1:
                b_cnt += 1
                
    print('#{} {} {}'.format(tt, b_cnt, w_cnt))

 

 

*앞으로는 문제풀이 글은 자주 업로드하지 않을 예정입니다.

반응형

bfs를 이용하여 해결했습니다.

bfs에 들어가는 값으로는 [[로봇위치1, 로봇위치2], 시간] 이 들어갑니다.

그리고 위치1의 값은 위치2보다 항상 작습니다.

[[0,0],[0,1]]

[[0,0],[1,0]]

 

문제는 다음에 방문할 위치에 대한 정보입니다.

 

회전에 대해서는 정사각형을 만들어서 처리했습니다.

만약 이 사각형에 1이 있다면 회전을 하지 못한다는 것을 의미합니다.

1이 없고 회전시킨 위치를 방문하지 않았다면, 큐에 (현재 시간+1)과 회전시킨 위치를 넣어줍니다. 

 

방문했는 지 확인하기 위해서 set을 이용했습니다. 문제는 list는 set에 들어갈 수 없기 때문에 tuple로 바꿔서 넣었습니다.

 

상하좌우는 일반적인 bfs문제와 동일하게 처리했습니다.

 

큐에서 꺼낸 위치에서 보드의 맨 마지막 위치가 있을 경우에는 현재 시간을 return 해줍니다.

 

from collections import deque

def solution(board):
    return bfs(board)


def is_out(y1,x1,y2,x2, n):
    if y1 < 0 or y1 >= n or y2 < 0 or y2 >= n or x1 < 0 or x1 >= n or x2 < 0 or x2 >= n:
        return True
    return False


def bfs(board):    
    vertical_squares = [[0,-1], [0,1]]
    horizontal_squares = [[-1,0], [1,0]]
    
    visited = set()
    
    q =deque()
    q.append([((0,0), (0,1)),0])
    
    visited.add(((0,0), (0,1)))
    
    while q:
        p,t= q.popleft()
        print(p,t)
        for y,x in p:
            if y==len(board)-1 and x == len(board)-1:
                return t
        
        #가로
        if p[0][0] == p[1][0]:
            for dy, dx in horizontal_squares:
                ny1, nx1, ny2, nx2 = p[0][0]+dy, p[0][1]+dx, p[1][0]+dy, p[1][1]+dx
                
                if is_out(ny1,nx2,ny2,nx2,len(board)):
                    continue
                    
                if board[ny1][nx1] == 1 or board[ny2][nx2] == 1:
                    continue
                
                npos = [[ny1, nx1], [ny2, nx2]]
                
                for i in range(2):
                    robot_pos = [[p[i][0], p[i][1]], [npos[i][0] ,  npos[i][1]]]
                    robot_pos.sort(key= lambda x : (x[0], x[1]))
                    
                    robot_pos = (tuple(robot_pos[0]), tuple(robot_pos[1]))
                    if robot_pos in visited:
                        continue
                    
                    visited.add(robot_pos)
                    q.append([robot_pos, t+1])
        #세로
        else:
            for dy, dx in vertical_squares:
                ny1, nx1, ny2, nx2 = p[0][0]+dy, p[0][1]+dx, p[1][0]+dy, p[1][1]+dx
                
                if is_out(ny1,nx2,ny2,nx2,len(board)):
                    continue
                    
                if board[ny1][nx1] == 1 or board[ny2][nx2] == 1:
                    continue
                
                npos = [[ny1, nx1], [ny2, nx2]]
                
                for i in range(2):
                    robot_pos = [[p[i][0], p[i][1]], [npos[i][0] , npos[i][1]]]
                    robot_pos.sort(key= lambda x : (x[0], x[1]))
                    
                    robot_pos = (tuple(robot_pos[0]), tuple(robot_pos[1]))
                    if robot_pos in visited:
                        continue
                    
                    visited.add(robot_pos)
                    q.append([robot_pos, t+1])
          
        direction = [[1,0],[0,1],[-1,0],[0,-1]]
        
        # 이동
        for dy, dx in direction:
            robot_pos = ((p[0][0]+dy, p[0][1]+dx),(p[1][0]+dy,p[1][1]+dx))
            
            if is_out(robot_pos[0][0], robot_pos[0][1], robot_pos[1][0], robot_pos[1][1], len(board)):
                continue
            if board[robot_pos[0][0]][robot_pos[0][1]] == 1 or board[robot_pos[1][0]][robot_pos[1][1]] == 1:
                    continue
        
            if robot_pos in visited:
                continue
            
            visited.add(robot_pos)
            q.append([robot_pos, t+1])

코드는 매우 지저분합니다.

반응형

이번 문제는 3단계 같지 않은 문제입니다.

 

단순하게 생각해서 각각의 셀을 그룹으로 지정합니다.

그리고 각 그룹의 값을 저장하고 있는 딕셔너리를 만듭니다.

 

그래서 업데이트를 할 경우에는 해당 셀의 그룹을 가져와서 딕셔너리의 값을 업데이트합니다.

merge는 모든 셀 중에서 merge하고자 하는 그룹에 해당하면, 그룹을 대상 그룹으로 업데이트 합니다.

2500 * 1000 이기 때문에 충분히 가능합니다.

 

unmerge는 그룹에 해당한다면, 새로운 값으로 그룹을 할당해줍니다. 중복되지 않게 하기 위해서 자기 위치에 해당하는 값을 넣어줍니다.

 

dic = {i : "" for i in range(50*50)}
board = [[j*50 + i for i in range(50)] for j in range(50)]

def solution(commands):
    answer = []

    for command in commands:
        command = list(command.split())
        
        if command[0] == "UPDATE":
            if len(command) == 4:
                update1(int(command[1])-1, int(command[2])-1, command[3])
            else:
                update2(command[1], command[2])
        elif command[0] == "MERGE":
            merge(int(command[1])-1, int(command[2])-1, int(command[3])-1, int(command[4])-1)
        elif command[0] == "UNMERGE":
            unmerge(int(command[1])-1, int(command[2])-1)
        elif command[0] == "PRINT":
            answer.append(print2(int(command[1])-1,int(command[2])-1))
        
    return answer


def update1(r, c, value):
    dic[board[r][c]] = value

def update2(value1, value2):
    for key in dic:
        if dic[key] == value1:
            dic[key] = value2

            
def merge(r1, c1, r2, c2):
    if board[r1][c1] == board[r2][c2]:
        return

    if dic[board[r1][c1]] != "":
        
        tmp = board[r2][c2]
        for i in range(50):
            for j in range(50):
                if board[i][j] == tmp:
                    board[i][j] = board[r1][c1]
                    
    else:
        tmp = board[r1][c1]
        for i in range(50):
            for j in range(50):
                if board[i][j] == tmp:
                    board[i][j] = board[r2][c2]

        
        
def unmerge(r, c):
    group = board[r][c]
    tmp_value = dic[group]
    
    for i in range(50):
        for j in range(50):
            if board[i][j] == group:
                board[i][j] = 50*i + j
                dic[50*i + j] = ""
                
    dic[board[r][c]] = tmp_value

def print2(r, c):
    if dic[board[r][c]] == "":
        return "EMPTY"
    else:
        return dic[board[r][c]]
반응형

이번 문제는 완전탐색에 대한 문제입니다.

 

일단 포화 이진 트리로 만들고, 탐색을 시작합니다.

루트노드부터 시작해서 제일 왼쪽 리프노트의 부모노드까지 내려옵니다. 이 서브트리가 올바른 트리인 지 확인합니다. 

 

어려운 점은 자식노드나 부모노드 간의 이동이 어려웠습니다.

 

from collections import deque
import itertools
import math

flag = True

def solution(numbers):
    answer = []
    
    for i in numbers:
        if i == 1:
            answer.append(1)
        else:
            an = ans(dec_to_bin(i))
            if an == -1:
                an =0
            answer.append(an)
    
    return answer


def dec_to_bin(number):
    ret = deque()
    while number!= 1:
        ret.appendleft(number%2)
        number = number // 2
        
    ret.appendleft(1)
    
    n = int(math.log2(len(ret))) + 1
    
    while 2**n-1 != len(ret):
        ret.appendleft(0)

    
    return ret

def ans(number):
    n = int(math.log2(len(number)))
    mid = len(number)//2

    return search(mid, number, n)


def search(idx, number, level):
    if (idx+1)%2 == 1:
        return number[idx]
    
    left = idx - 2**(level-1)
    right = idx + 2**(level-1)
    
    
    l = search(left, number, level-1)
    r = search(right, number, level-1)
    
    if l == -1 or r == -1:
        return -1

    if number[idx] == 0:
        if l == 0 and r == 0:
            return 0
        else:
             return -1

    else:
        return  1
반응형

이번 문제는 다익스트라를 통해 풀었다.

 

원래 처음에는 경로를 추적할 수 있도록, 거리를 측정하는 배열에 [이전 노드, 거리] 값을 저장하도록 했었다.

문제는 다익스트라는 해당 노드까지 최단거리로 갈 수 있는 경로가 많은 경우, g와 h를 포함하지 않을 수 있기 때문에 문제가 되었다.

 

그래서 s -> g -> h -> 목적지, s -> h -> g -> 목적지를 구하기 위해, s ,g, h를 시작점으로 각각 다익스트라 통해 최단 거리를 구한다.

 

import heapq
import sys

from collections import deque



def djk(board, s, n):

    hq = []
    
    dst = deque([987654321 for _ in range(n+1)])
    
    heapq.heappush(hq, (0, s))
    dst[s] = 0
    
    
    while hq:
        d, node = heapq.heappop(hq)
           
        if dst[node] < d:
            continue
        
        for i in board[node]:
            
            if board[node][i] + d < dst[i]:
                dst[i] = board[node][i] + d
                heapq.heappush(hq, (dst[i], i))
    
    return dst


T = int(sys.stdin.readline())


for _ in range(T):
    n, m , t = map(int, sys.stdin.readline().split())
    s, g, h = map(int, sys.stdin.readline().split())
    
    board = [{} for _ in range(n+1)]
    
    for _ in range(m):
        a, b, d = map(int, sys.stdin.readline().split())
        
        board[a][b] = d
        board[b][a] = d
    
    dst_condidate = deque()
    
    for _ in range(t):
        dst_condidate.append(int(sys.stdin.readline()))
    
    ss = djk(board, s, n)
    gg = djk(board, g, n)
    hh = djk(board, h, n)
    
    ans = []
    
    for dd in dst_condidate: 
        if ss[dd] == ss[g] + board[g][h] + hh[dd] or ss[dd] == ss[h] + board[h][g]+ gg[dd]:
            ans.append(dd)
            
    ans.sort()
    for w in ans:
        print(w, end=' ')
    print()

원래 ans에 str(dd)를 append 하고 join을 이용하려 했었는데, str은 sort가 integer 형이랑 결과가 다르게 나온다. 이 점에서 매우 시간을 많이 소비했다.

반응형

 

이번 문제는 백준 6087 레이저 통신 문제입니다.

 

다익스트라를 이용해서 풀었습니다.

각 지점의 최소거리(거울 개수)를 구하고, 이를 이용하여 또 다른 레이저 좌표까지 탐색하도록 했습니다.

 

중요한 점은 이전에 어떤 방향으로 진행했는지 알아야 합니다.

그래야지 거울 개수를 알 수 있기 때문입니다.

 

 

import heapq


def dij(razer_pos, board, r, c):
    
    hq = []
    
    direction = {}
    direction['up'] = {'up':(1,0), 'left':(0,-1), 'right' : (0,1)}
    direction['down'] = {'down':(-1,0), 'left':(0,-1), 'right' : (0,1)}
    direction['left'] = {'left' : (0,-1), 'up': (1,0), 'down' :(-1,0)}
    direction['right'] = {'right' : (0,1), 'up': (1,0), 'down' :(-1,0)}
    
    board_dist = [[100001 for _ in range(C)] for _ in range(R)]
    
    heapq.heappush(hq, (0, (razer_pos[0], 'up')))
    heapq.heappush(hq, (0, (razer_pos[0], 'down')))
    heapq.heappush(hq, (0, (razer_pos[0], 'left')))
    heapq.heappush(hq, (0, (razer_pos[0], 'right')))

    while hq:
        dist, prev = heapq.heappop(hq)
        
        pos, prev_dir = prev
        y, x = pos
        
        if y == razer_pos[1][0] and x == razer_pos[1][1]:
            print(dist)
            break
        
        if dist > board_dist[y][x]:
            continue
        
        for key, val in direction[prev_dir].items():
            dir_y, dir_x = val
            dir_y, dir_x = dir_y + y, dir_x + x
            
            if dir_y >= r or dir_y < 0 or dir_x >= c or dir_x < 0:
                continue
            
            if board[dir_y][dir_x] != '*' :

                now_dist = 0
                
                if key != prev_dir:
                    now_dist += 1
                    
                if dist + now_dist <= board_dist[dir_y][dir_x]:
                    heapq.heappush(hq, (dist+now_dist, ((dir_y,dir_x),key)))
                    board_dist[dir_y][dir_x] = dist+now_dist
                    

C, R = map(int, input().split())

board = []

razer_pos = []

for i in range(R):
    board.append(list(input()))
    
    for j in range(C):
        if board[i][j] == 'C':
            razer_pos.append((i,j))
            




dij(razer_pos, board, R, C)

 

처음에는 다익스트라 문제 손도 못 댔는데, 이번 문제는 40분 정도 걸렸네요.

 

반응형

접근 방법

단순한 단순탐색 문제.

 

방문했던 노드로 다시 돌아올 수 있다는 점이 차별점입니다..

방문했던 노드와 인접한 모든 노드를 탐색하면 됩니다.

 

저는 lv2인 양궁대회보다 이 문제가 더 쉽다고 느껴졌습니다.

 

import java.util.List;
import java.util.ArrayList;

class Solution {
    public int[][] graph = null;
    public int n = 0;
    public int maxSheep = 1;
    
    public int solution(int[] info, int[][] edges) {
        this.n = info.length;
        this.graph = new int[this.n][this.n];
        for(int i = 0; i < edges.length; i++){
            this.graph[edges[i][0]][edges[i][1]] = 1;
            this.graph[edges[i][1]][edges[i][0]] = 1;
        }
        
        int[] visited = new int[this.n];
        visited[0] = 1;
        int answer = 0;
        search(info, visited, 0, 1);
        return maxSheep;
    }
    
    public List<Integer> findNext(int[] info, int[] visited, int wolfNum, int sheepNum){
        List<Integer> n = new ArrayList<>();
        
        for(int i = 0; i < this.n; i++){
            if(visited[i] == 1){
                for(int j = 0; j < this.n; j++){
                    if(this.graph[i][j] == 1 && !(n.contains(j)) && visited[j] == 0){
                        int tmpWolfNum = wolfNum;
                        int tmpSheepNum = sheepNum;
                        
                        if(info[j] == 1){
                            tmpWolfNum +=1;
                        }
                        else{
                            tmpSheepNum +=1;
                        }
                        
                        if(tmpWolfNum < tmpSheepNum){
                            n.add(j);
                        }
                    }
                }
            }
        }
        return n;
    }
    
    public void search(int[] info, int[] visited, int wolfNum, int sheepNum){
        List<Integer> n = findNext(info, visited, wolfNum, sheepNum);
        if(n.size() == 0){
            if(maxSheep < sheepNum){
                maxSheep = sheepNum;
            }
            
            return;
        }
        
        for(int i = 0; i < n.size(); i++){
            int nextNode = n.get(i);
            visited[nextNode] = 1;
            if(info[nextNode]==0){
                search(info, visited, wolfNum, sheepNum + 1);
            }
            else{
                search(info, visited, wolfNum+1, sheepNum);
            }
            visited[nextNode] = 0;
        }
        
        return;
    }
}
반응형

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

 

2583번: 영역 구하기

첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오른쪽 위 꼭짓점의 x, y좌표값이 빈칸을 사이에 두고 차례로 주어진다. 모눈종이의 왼쪽 아래 꼭짓점의 좌표는 (0,0)이고, 오른쪽 위 꼭짓점의 좌표는(N,M)이다. 입력되는 K개의 직사각형들이 모눈종이 전체를 채우는 경우는 없다.

www.acmicpc.net

 

#include <iostream>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;

int main(){
	int map[100][100] = { 0 };
	int m, n, k;
	int cnt = 0;
	int dx[4] = { 0, 0, 1, -1 };
	int dy[4] = { 1, -1, 0, 0 };
	vector<int> ret;
	bool visited[100][100] = { 0 };
	cin >> m >> n >> k;

	for (int i = 0; i < k; i++){
		int r_x, r_y, l_x, l_y;
		cin >> l_x >> l_y >> r_x >> r_y;
		l_y = m-1 - l_y;
		r_y = m-1 - r_y;
		for (int j = l_y; j > r_y; j--){
			for (int k = l_x; k < r_x; k++){
				map[j][k] = 1;
			}
		}
	}

	for (int i = 0; i < m; i++){
		for (int j = 0; j < n; j++){
			queue<pair<int, int>> q;
			int tmp_ret = 0;
			if (visited[i][j] || map[i][j]) continue;
			cnt += 1;
			q.push({ i, j }); visited[i][j] = true;


			while (!q.empty()){
				tmp_ret += 1;
				int x = q.front().second, y = q.front().first;
				q.pop();

				for (int k = 0; k < 4; k++){
					int xx = x + dx[k], yy = y + dy[k];

					if (xx >= n || yy >= m || xx < 0 || yy < 0) continue;
					if (map[yy][xx] == 1 ||visited[yy][xx]) continue;
					q.push({ yy, xx }); visited[yy][xx] = 1;
				}
			}

			ret.push_back(tmp_ret);
		}
	}

	sort(ret.begin(), ret.end());

	cout << cnt << endl;
	for (int i = 0; i < cnt; i++){
		cout << ret[i] << ' ';
	}

}
반응형

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

 

2110번: 공유기 설치

첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (1 ≤ xi ≤ 1,000,000,000)가 한 줄에 하나씩 주어진다.

www.acmicpc.net

#include <iostream>
#include <algorithm>
using namespace std;

int main(){
	int n, c;
	int arr[200000];
	
	cin >> n >> c;
	for(int i = 0; i < n; i++) scanf("%d", arr+i);
	sort(arr,arr+n);
	
	int left = 0, right = arr[n-1]-arr[0]+1;

	while(left + 1 < right){
		int mid = (left+right)/2;
		int cnt = 1;
		int start = arr[0];
		
		for(int i = 1; i < n; i++){
			if(arr[i] - start >= mid){
				cnt++;
				start =arr[i];
			}
		}
		
		if(cnt < c) right = mid;
		else		 left = mid;
		
	}
	
	cout << left;
	
}

 

mid를 공유기 간의 거리로 설정하고 풀었습니다.

반응형

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

 

2343번: 기타 레슨

강토는 자신의 기타 레슨 동영상을 블루레이로 만들어 판매하려고 한다. 블루레이에는 총 N개의 레슨이 들어가는데, 블루레이를 녹화할 때, 레슨의 순서가 바뀌면 안된다. 순서가 뒤바뀌는 경우에는 레슨의 흐름이 끊겨, 학생들이 대혼란에 빠질 수 있기 때문이다. 즉, i번 레슨과 j번 레슨을 같은 블루레이에 녹화하려면 i와 j 사이의 모든 레슨도 같은 블루레이에 녹화해야 한다. 강토는 이 블루레이가 얼마나 팔릴지 아직 알 수 없기 때문에, 블루레이의 개수를 가급

www.acmicpc.net

 

길이(mid)를 정해두고, 만약 이 길이를 넘거 같아지면 새로운 블루레이 cd에 길이를 저장하는 방식으로 풀었습니다.

	#include <iostream>
	#include <algorithm>
	#define MAX_SIZE 100000
	using namespace std;
	
	int main(){
		int n, m;
		int arr[MAX_SIZE] = {0};
		int left = 0, right = 0;
		cin >> n >> m;
		
		for(int i = 0; i < n; i++){
			scanf("%d", &arr[i]);
			left = max(left,arr[i]);
		}
		right = 1000000000/m;

		
		while(left +1< right){
			int mid = (right + left) /2;
			int sum = 0, cnt = 0;
			
			for(int i = 0; i < n; i++){
				
				if(sum + arr[i]>= mid){
					cnt++;
					sum = 0;
				}
				sum += arr[i];
			}
			
			if(sum!=0) cnt++;
			
			if(cnt <= m) right = mid;
			else		left = mid;
		}
		
		
		
		cout << left;
		
	}

 

 

반응형

+ Recent posts