<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Social Developer</title>
    <link>https://sdesigner.tistory.com/</link>
    <description>어제보다 한 걸음 더</description>
    <language>ko</language>
    <pubDate>Sun, 12 Apr 2026 23:02:58 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>SDev</managingEditor>
    <image>
      <title>Social Developer</title>
      <url>https://tistory1.daumcdn.net/tistory/3569099/attach/5fa2c93254e947ebbd924e9b934ed160</url>
      <link>https://sdesigner.tistory.com</link>
    </image>
    <item>
      <title>블로그 이전</title>
      <link>https://sdesigner.tistory.com/123</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;얼마전 휴대폰 번호도 바꾸고, 카카오 계정도 변경한 뒤 문제가 생겼는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로그 계정이 기존 카카오 계정에 귀속되어 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문의 결과 같은 명의의 다른 카카오 계정으로 블로그를 넘기지도 못해서, 아깝지만 이참에 블로그도 바꿔보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바뀌는 블로그는 &lt;a href=&quot;https://honey-berry.tistory.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://honey-berry.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1726575492000&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;honeyberry 님의 기술 블로그&quot; data-og-description=&quot;honeyberry 님의 기술 블로그 입니다.&quot; data-og-host=&quot;honey-berry.tistory.com&quot; data-og-source-url=&quot;https://honey-berry.tistory.com/&quot; data-og-url=&quot;https://honey-berry.tistory.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/g8N2a/hyW6J6BRh0/p4wIhX6UzQIm0KeBAZXoP0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/pWp1v/hyW22022Nh/k1YsZWpOco5cBoJlOIwvvk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/FbTiZ/hyW6zXeiLk/MOcPPkb4U85mrsK4KkLNk1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://honey-berry.tistory.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://honey-berry.tistory.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/g8N2a/hyW6J6BRh0/p4wIhX6UzQIm0KeBAZXoP0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/pWp1v/hyW22022Nh/k1YsZWpOco5cBoJlOIwvvk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/FbTiZ/hyW6zXeiLk/MOcPPkb4U85mrsK4KkLNk1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;honeyberry 님의 기술 블로그&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;honeyberry 님의 기술 블로그 입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;honey-berry.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 다시 꾸준히 해보자!&lt;/p&gt;</description>
      <category>Life</category>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/123</guid>
      <comments>https://sdesigner.tistory.com/123#entry123comment</comments>
      <pubDate>Tue, 17 Sep 2024 21:18:22 +0900</pubDate>
    </item>
    <item>
      <title>linux/unix 환경에서 disk filesystem 조회하기</title>
      <link>https://sdesigner.tistory.com/122</link>
      <description>&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;$ df -h
Filesystem       Size   Used  Avail Capacity iused     ifree %iused  Mounted on&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-t 옵션은 human readable의 약자로, 읽기 쉽게 출력하도록 하는 옵션이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Filesystem: 파일 시스템의 이름 또는 식별자.&lt;/li&gt;
&lt;li&gt;Size: 파일 시스템의 총 크기.&lt;/li&gt;
&lt;li&gt;Used: 파일 시스템에서 사용 중인 공간의 크기.&lt;/li&gt;
&lt;li&gt;Avail: 파일 시스템에서 사용 가능한 공간의 크기.&lt;/li&gt;
&lt;li&gt;Use%: 사용 중인 공간의 비율.&lt;/li&gt;
&lt;li&gt;Mounted on: 파일 시스템이 마운트된 디렉토리 또는 위치.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Skill/Infra</category>
      <category>df</category>
      <category>disk</category>
      <category>File System</category>
      <category>Linux</category>
      <category>Mac</category>
      <category>파일시스템</category>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/122</guid>
      <comments>https://sdesigner.tistory.com/122#entry122comment</comments>
      <pubDate>Mon, 19 Feb 2024 17:11:57 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] 10869번 Golang 풀이</title>
      <link>https://sdesigner.tistory.com/121</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2021-12-13 오후 11.45.44.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;1554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NwS2e/btrnLHkhGtb/9RU7oMT9gRRCnIVI4R9Xr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NwS2e/btrnLHkhGtb/9RU7oMT9gRRCnIVI4R9Xr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NwS2e/btrnLHkhGtb/9RU7oMT9gRRCnIVI4R9Xr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNwS2e%2FbtrnLHkhGtb%2F9RU7oMT9gRRCnIVI4R9Xr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1564&quot; height=&quot;1554&quot; data-filename=&quot;스크린샷 2021-12-13 오후 11.45.44.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;1554&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Golang에 보다 익숙해지기 위해 Golang으로 가벼운 알고리즘 문제들의 풀이를 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 답안 소스는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1639406833050&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
)

func main() {
	var a, b int
	fmt.Scanln(&amp;amp;a, &amp;amp;b)

	fmt.Println(a + b)
	fmt.Println(a - b)
	fmt.Println(a * b)
	fmt.Println(a / b)
	fmt.Println(a % b)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 문제이지만 여기서 확인할만한 점은 golang의 int 자료형의 범위, fmt.scanln 함수 정도일 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;golang에서는 int8, int32, int64, uint8... 등 숫자와 관련된 다양한 자료형이 있는데 여기서 사용한 int의 크기는 시스템에 따라 결정된다. 이 문제에서는 a, b가 모두 10,000보다 같거나 작으므로 곱해도 1억 이하의 수다. 32비트 시스템에서 동작되더라도 범위를 벗어날 일은 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Golang에서의 숫자 관련 자료형 확인하기 : &lt;a href=&quot;http://pyrasis.com/book/GoForTheReallyImpatient/Unit08&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://pyrasis.com/book/GoForTheReallyImpatient/Unit08&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 fmt.scanln 함수를 살펴본다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2021-12-13 오후 11.54.42.png&quot; data-origin-width=&quot;1654&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci1NOT/btrnQ46mXQh/RKDXSk1Hi9aKzk5IU3KVtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci1NOT/btrnQ46mXQh/RKDXSk1Hi9aKzk5IU3KVtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci1NOT/btrnQ46mXQh/RKDXSk1Hi9aKzk5IU3KVtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci1NOT%2FbtrnQ46mXQh%2FRKDXSk1Hi9aKzk5IU3KVtK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1654&quot; height=&quot;320&quot; data-filename=&quot;스크린샷 2021-12-13 오후 11.54.42.png&quot; data-origin-width=&quot;1654&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Golang은 공식 사이트에서 각종 패키지에 대한 설명이 잘 나와있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;a href=&quot;https://pkg.go.dev/fmt#Scanln&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pkg.go.dev/fmt#Scanln&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명에 잘 나와있듯 Scan 함수와 유사하면서 개행문자를 만났을 때, 마지막 item 이후의 개행 혹은 EOF(End of File)일 때 Scan을 멈춘다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(EOF : 컴퓨팅에서 더이상 읽어올 데이터가 없음)&lt;/p&gt;</description>
      <category>Algorithms</category>
      <category>Go 프로그래밍</category>
      <category>Go언어</category>
      <category>백준 10869</category>
      <category>백준 10869 Go 풀이</category>
      <category>백준 10869 Golang 풀이</category>
      <category>백준 사칙연산</category>
      <category>백준 사칙연산 Go</category>
      <category>백준 사칙연산 Golang</category>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/121</guid>
      <comments>https://sdesigner.tistory.com/121#entry121comment</comments>
      <pubDate>Mon, 13 Dec 2021 23:59:48 +0900</pubDate>
    </item>
    <item>
      <title>[Elasticsearch] Elasticsearch는 멀티테넌시?</title>
      <link>https://sdesigner.tistory.com/119</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;416&quot; data-filename=&quot;elasticsearch.png&quot; width=&quot;400&quot; height=&quot;208&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n6MCa/btq8ZjkaShf/WNEKLOsDU10OhD8IZFAkuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n6MCa/btq8ZjkaShf/WNEKLOsDU10OhD8IZFAkuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n6MCa/btq8ZjkaShf/WNEKLOsDU10OhD8IZFAkuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn6MCa%2Fbtq8ZjkaShf%2FWNEKLOsDU10OhD8IZFAkuk%2Fimg.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;416&quot; data-filename=&quot;elasticsearch.png&quot; width=&quot;400&quot; height=&quot;208&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 2021 멋쟁이사자처럼 세렝게티 올빼미 프로젝트에서 카카오엔터프라이즈와 k8s 과정을 하면서 Metric Monitoring &amp;amp; Logging 기술 중 Elasticsearch를 알아보고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Elasticsearch의 특징 중 하나가 멀티테넌시(Multi-tenancy)라는데, 이 개념에 대해 전혀 몰랐기 때문에 기술을 익히면서 찾아보고 지나갔는데 시간이 지나고 다시 봤을 때 기억이 나지 않아 여기 정리해두려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;멀티테넌시(Multi-tenancy)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tenancy의 뜻을 찾아보면, '(주택, 토지 등의)차용[임차/소작]'으로 소개되어 있다. 쉽게 말해 빌려 쓴다는 뜻이다. 멀티테넌시를 구글링해보면 단일테넌시와 구분지어 설명되어 있는 글을 쉽게 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단일 테넌시&lt;/b&gt;는 &lt;u&gt;하나의 소프트웨어나 인스턴스가 하나의 사용자 혹은 사용자그룹을 위해 작동하는 아키텍처&lt;/u&gt;,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;멀티테넌시&lt;/b&gt;는 &lt;u&gt;하나의 소프트웨어나 인스턴스가 여러 사용자 혹은 사용자그룹을 위해 작동하는 아키텍처&lt;/u&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 예를 들면, &lt;b&gt;웹메일 서비스&lt;/b&gt;로 생각해볼 수 있다. &lt;b&gt;웹메일 서비스는 멀티테넌시 구조&lt;/b&gt;로 동작하고 있다. 많은 사람들이 크게 하나의 웹메일 서비스(gmail, naver...)를 이용해 메일을 주고받고 있다. 하지만 여기서 중요한 것은 &lt;b&gt;여러 사용자 및 사용자 그룹이 사용하더라도 각각이 독립적으로 이용한다는 사실&lt;/b&gt;이다. 모든 사용자의 메일 데이터는 각 메일 서비스 제공 기업에서 관리하지만, &lt;b&gt;사용자는 나를 제외한 다른 사람들의 메일 자료에 접근할 수 없고 마치 나만을 위한 서비스&lt;/b&gt;처럼 느껴진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 멀티테넌시가 아닌 &lt;b&gt;단일테넌시라면&lt;/b&gt; 어땠을까? 단일 사용자 및 그룹을 위해 작동하는 아키텍처라는 점에서 모든 사용자가 각 메일 프로그램을 다운로드하고, 각 기기에서 설치한 뒤 각자의 기기 내에서 메일 데이터를 보관하고 사용하며 심지어 노트북에서 받은 메일은 스마트폰에서 읽을 수 없을 수도 있다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;멀티테넌시 아키텍처의 장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비용 절감&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어를 지탱하는 하드웨어 측면에서 바라보면 규모의 경제로 인해 자원 구축 비용 절감, IT 리소스를 유연하게 할당할 수 있는 유연성을 포함해 새로운 버전이 나와도 장비 쪽 소프트웨어만 업데이트하면 모든 사용자가 새로운 기능을 사용할 수 있어 관리 비용도 크게 절감할 수 있다. 크게 최근 많이 사용되고 있는 클라우드 서비스와 맥락을 같이한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;편리한 데이터 통합&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 시스템과 소프트웨어를 여러 사용자가 공유하는 구조이므로 사용자별 데이터가 사실상 같은 저장소에 저장된다. 결과적으로 대규모 데이터를 모을 수 있고, 분석하는 작업도 더 편리해진다. 최근 분석에 대한 수요가 커지고, 데이터의 양도 급속도로 거대해지면서 더 두드러지고 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;멀티테넌시 아키텍처의 단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개인화를 지원하기 위한 정교한 아키텍처 구현&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인화를 지원하기 위해 그만큼 더 정교한 아키텍처 설계가 필요하다. 자칫 소프트웨어나 인스턴스 하나의 장애가 수많은 사용자 및 사용자그룹에게 모두 피해를 입힐 수 있고, 일부 사용자를 위한 업데이트가 또 다른 사용자에게는 오히려 불편함을 유발할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;보안&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조적으로 사용자별로 완전히 구분되어 있는 것처럼 보이지만, 실상은 단일 저장소에 여러 사용자 및 사용자그룹의 데이터가 보관되어 있다. 따라서 각 단위의 데이터가 서로 섞이지 않도록 해야 하고, 몸집이 커지는 만큼 해킹 위협에 대해서도 그만한 보안 체계를 갖춰야만 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;멀티테넌시 용어의 다양한 쓰임&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 일반적인 소프트웨어 관점에서의 멀티테넌시 구조를 살펴봤는데, &lt;b&gt;쿠버네티스와 같은 컨테이너 오케스트레이션 플랫폼에서 멀티테넌시라는 용어는 또 조금 다르게 쓰인다&lt;/b&gt;. &lt;b&gt;소프트웨어 관점&lt;/b&gt;에서 tenancy 대상인 &lt;b&gt;tenant(사용자)는&lt;/b&gt; &lt;b&gt;사용자, 사용자 그룹&lt;/b&gt;이지만, &lt;b&gt;컨테이너 오케스트레이션 플랫폼에서는 프로젝트 단위가 tenancy&lt;/b&gt;이기 때문이다. 즉 컨테이너 오케스트레이션 플랫폼에서 멀티테넌시라는 용어는 &lt;b&gt;대개 여러개의 프로젝트를 서비스하는 단일 클러스터&lt;/b&gt;를 의미하고, 이 클러스터는 서로 분리 실행하도록 설정되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 다시 Elasticsearch로 돌아가보자. &lt;b&gt;Elasticsearch는 왜 멀티테넌시 구조인가?&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Elasticsearch는 여러 개의 분리된 인덱스(Indecies)를 그룹으로 저장&lt;/b&gt;한다. 인덱스는 관계형 DB에서 데이터베이스와 대응되는 개념이다. 관계형 DB에서 다른 데이터베이스의 데이터를 검색하려면 별도의 커넥션을 생성해야하는데, &lt;b&gt;Elasticsearch에서는 서로 다른 인덱스의 데이터를 하나의 쿼리로 묶어서 검색하고 하나의 출력으로 모아줄 수 있다&lt;/b&gt;. 이 때문에 Elasticsearch를 멀티테넌시 구조라고 소개하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 자료&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ITWorld용어풀이| 멀티테넌시(Multitenancy) -&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.itworld.co.kr/news/101255&quot;&gt;https://www.itworld.co.kr/news/101255&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RedHat, 클라우드컴퓨팅 멀티테넌시란? -&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.redhat.com/ko/topics/cloud-computing/what-is-multitenancy&quot;&gt;https://www.redhat.com/ko/topics/cloud-computing/what-is-multitenancy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ElasticSearch(6.1.1) 알아보기 - &lt;a href=&quot;https://chuckolet.tistory.com/47&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://chuckolet.tistory.com/47&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Skill/Etc.</category>
      <category>Elasticsearch</category>
      <category>tenancy</category>
      <category>멀티테넌시</category>
      <category>테넌시</category>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/119</guid>
      <comments>https://sdesigner.tistory.com/119#entry119comment</comments>
      <pubDate>Tue, 6 Jul 2021 23:55:39 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] 5373번 큐빙 Java 풀이</title>
      <link>https://sdesigner.tistory.com/118</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1866&quot; data-origin-height=&quot;1596&quot; data-filename=&quot;스크린샷 2021-07-06 오후 1.13.38.png&quot; width=&quot;642&quot; height=&quot;549&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buMZty/btq8YXmUR6M/DPzh5CgYcFW0LwjqXS3NdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buMZty/btq8YXmUR6M/DPzh5CgYcFW0LwjqXS3NdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buMZty/btq8YXmUR6M/DPzh5CgYcFW0LwjqXS3NdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuMZty%2Fbtq8YXmUR6M%2FDPzh5CgYcFW0LwjqXS3NdK%2Fimg.png&quot; data-origin-width=&quot;1866&quot; data-origin-height=&quot;1596&quot; data-filename=&quot;스크린샷 2021-07-06 오후 1.13.38.png&quot; width=&quot;642&quot; height=&quot;549&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;720&quot; data-filename=&quot;스크린샷 2021-06-26 오전 8.12.40.png&quot; width=&quot;672&quot; height=&quot;276&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dubRmf/btq8auUVGtx/NTlh3j4QKXZ5ckTiNKhWHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dubRmf/btq8auUVGtx/NTlh3j4QKXZ5ckTiNKhWHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dubRmf/btq8auUVGtx/NTlh3j4QKXZ5ckTiNKhWHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdubRmf%2Fbtq8auUVGtx%2FNTlh3j4QKXZ5ckTiNKhWHK%2Fimg.png&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;720&quot; data-filename=&quot;스크린샷 2021-06-26 오전 8.12.40.png&quot; width=&quot;672&quot; height=&quot;276&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하루동안 7시간에 걸쳐 문제를 풀었다. 문제 출력으로는 큐브의 윗 면만 출력하면 되는데, 히든 케이스를 위해 디버깅하는 과정에서 전체 큐브의 변화를 체크하지 않으면 디버깅이 더 어렵기 때문에 다른 면의 움직임까지 찍어보면서 문제를 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적인 문제 풀이 방법은 직접 큐브의 한 번의 회전 움직임을 모두 직접 지정해두는 방식으로 해결했다. 이전에 주사위 굴리기(14499번) 문제와 약간 유사했던 것 같은데, 다른 방식으로 해결할 수도 있는지는 아직 모르겠다. 내 경우에는 문제 풀이 접근을 찾았더라도 직접 코드를 작성하는 시간과 디버깅에 쓴 시간이 매우 길었기 때문에 더 좋은 풀이가 있지 않을까..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 풀이에서 독특한 점은 큐브를 3차원 배열로 저장하지 않고, 2차원 배열로 저장했다는 점이다. 아래와 같이 큐브의 한 면 내에서 인덱스를 0~8까지 지정해 생성하고 관리해주는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 16.0465%; height: 115px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀이 접근도 접근이지만, 디버깅이 매우 어렵다. 내 경우에는 직접 큐브 회전을 시뮬레이션할 수 있는 웹사이트를 찾아 이를 디버깅에 활용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rubiks-cube-solver.com/fr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://rubiks-cube-solver.com/fr/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1624663365762&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Programme de r&amp;eacute;solution Rubik's Cube&quot; data-og-description=&quot;Le programme de r&amp;eacute;solution Rubik's Cube en ligne calcule les &amp;eacute;tapes n&amp;eacute;cessaires pour r&amp;eacute;soudre un Rubik's Cube m&amp;eacute;lang&amp;eacute;. Entrez les couleurs de votre puzzle, cliquez sur R&amp;eacute;soudre&quot; data-og-host=&quot;rubiks-cube-solver.com&quot; data-og-source-url=&quot;https://rubiks-cube-solver.com/fr/&quot; data-og-url=&quot;https://rubiks-cube-solver.com/fr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bp7UM9/hyKGnQgrfx/gECVuZcM31MbaIkMuDEjUk/img.jpg?width=1000&amp;amp;height=600&amp;amp;face=0_0_1000_600&quot;&gt;&lt;a href=&quot;https://rubiks-cube-solver.com/fr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://rubiks-cube-solver.com/fr/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bp7UM9/hyKGnQgrfx/gECVuZcM31MbaIkMuDEjUk/img.jpg?width=1000&amp;amp;height=600&amp;amp;face=0_0_1000_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Programme de r&amp;eacute;solution Rubik's Cube&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Le programme de r&amp;eacute;solution Rubik's Cube en ligne calcule les &amp;eacute;tapes n&amp;eacute;cessaires pour r&amp;eacute;soudre un Rubik's Cube m&amp;eacute;lang&amp;eacute;. Entrez les couleurs de votre puzzle, cliquez sur R&amp;eacute;soudre&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;rubiks-cube-solver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1624663297323&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
	static int cases;
	static char[][] cube = new char[6][9];

	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		
		cases = Integer.parseInt(br.readLine());
		for(int k = 0; k &amp;lt; cases; k++) {
			init();
			int operNum = Integer.parseInt(br.readLine());
			String[] opers = new String[operNum];
			st = new StringTokenizer(br.readLine());
			
			for(int i = 0; i &amp;lt; operNum; i++) {
				opers[i] = st.nextToken();
				rotate(opers[i]);
			}
			printUp();
		}
	}
	
	public static void rotate(String oper) {
		char[][] temp = copy();
		int index = -1;
		
		if(oper.charAt(0) == 'U') {
			index = 0;
		}else if(oper.charAt(0) == 'D') {
			index = 1;
		}else if(oper.charAt(0) == 'F') {
			index = 2;
		}else if(oper.charAt(0) == 'B') {
			index = 3;
		}else if(oper.charAt(0) == 'L') {
			index = 4;
		}else if(oper.charAt(0) == 'R') {
			index = 5;
		}
		
		if(oper.charAt(1) == '+') {
			// 돌린 면의 숫자 재배치
			cube[index][0] = temp[index][6]; cube[index][1] = temp[index][3]; cube[index][2] = temp[index][0];
			cube[index][3] = temp[index][7]; cube[index][4] = temp[index][4]; cube[index][5] = temp[index][1];
			cube[index][6] = temp[index][8]; cube[index][7] = temp[index][5]; cube[index][8] = temp[index][2];
			if(oper.charAt(0) == 'U') {
				cube[2][0] = temp[5][0]; cube[2][1] = temp[5][1]; cube[2][2] = temp[5][2];
				cube[4][0] = temp[2][0]; cube[4][1] = temp[2][1]; cube[4][2] = temp[2][2];
				cube[3][0] = temp[4][0]; cube[3][1] = temp[4][1]; cube[3][2] = temp[4][2];
				cube[5][0] = temp[3][0]; cube[5][1] = temp[3][1]; cube[5][2] = temp[3][2];
			}else if(oper.charAt(0) == 'D') {
				cube[5][6] = temp[2][6]; cube[5][7] = temp[2][7]; cube[5][8] = temp[2][8];
				cube[3][6] = temp[5][6]; cube[3][7] = temp[5][7]; cube[3][8] = temp[5][8];
				cube[4][6] = temp[3][6]; cube[4][7] = temp[3][7]; cube[4][8] = temp[3][8];
				cube[2][6] = temp[4][6]; cube[2][7] = temp[4][7]; cube[2][8] = temp[4][8];
			}else if(oper.charAt(0) == 'F') {
				cube[5][0] = temp[0][6]; cube[5][3] = temp[0][7]; cube[5][6] = temp[0][8];
				cube[1][2] = temp[5][0]; cube[1][1] = temp[5][3]; cube[1][0] = temp[5][6];
				cube[4][2] = temp[1][0]; cube[4][5] = temp[1][1]; cube[4][8] = temp[1][2];
				cube[0][8] = temp[4][2]; cube[0][7] = temp[4][5]; cube[0][6] = temp[4][8];
			}else if(oper.charAt(0) == 'B') {
				cube[4][6] = temp[0][0]; cube[4][3] = temp[0][1]; cube[4][0] = temp[0][2];
				cube[1][6] = temp[4][0]; cube[1][7] = temp[4][3]; cube[1][8] = temp[4][6];
				cube[5][8] = temp[1][6]; cube[5][5] = temp[1][7]; cube[5][2] = temp[1][8];
				cube[0][0] = temp[5][2]; cube[0][1] = temp[5][5]; cube[0][2] = temp[5][8];
			}else if(oper.charAt(0) == 'L') {
				cube[2][0] = temp[0][0]; cube[2][3] = temp[0][3]; cube[2][6] = temp[0][6];
				cube[1][0] = temp[2][0]; cube[1][3] = temp[2][3]; cube[1][6] = temp[2][6];
				cube[3][8] = temp[1][0]; cube[3][5] = temp[1][3]; cube[3][2] = temp[1][6];
				cube[0][6] = temp[3][2]; cube[0][3] = temp[3][5]; cube[0][0] = temp[3][8];
			}else if(oper.charAt(0) == 'R') {
				cube[3][6] = temp[0][2]; cube[3][3] = temp[0][5]; cube[3][0] = temp[0][8];
				cube[1][8] = temp[3][0]; cube[1][5] = temp[3][3]; cube[1][2] = temp[3][6];
				cube[2][2] = temp[1][2]; cube[2][5] = temp[1][5]; cube[2][8] = temp[1][8];
				cube[0][2] = temp[2][2]; cube[0][5] = temp[2][5]; cube[0][8] = temp[2][8];
			}
		}else if(oper.charAt(1) == '-') {
			// 돌린 면의 숫자 재배치
			cube[index][0] = temp[index][2]; cube[index][1] = temp[index][5]; cube[index][2] = temp[index][8];
			cube[index][3] = temp[index][1]; cube[index][4] = temp[index][4]; cube[index][5] = temp[index][7];
			cube[index][6] = temp[index][0]; cube[index][7] = temp[index][3]; cube[index][8] = temp[index][6];
			if(oper.charAt(0) == 'U') {
				cube[5][0] = temp[2][0]; cube[5][1] = temp[2][1]; cube[5][2] = temp[2][2];
				cube[2][0] = temp[4][0]; cube[2][1] = temp[4][1]; cube[2][2] = temp[4][2];
				cube[4][0] = temp[3][0]; cube[4][1] = temp[3][1]; cube[4][2] = temp[3][2];
				cube[3][0] = temp[5][0]; cube[3][1] = temp[5][1]; cube[3][2] = temp[5][2];
			}else if(oper.charAt(0) == 'D') {
				cube[2][6] = temp[5][6]; cube[2][7] = temp[5][7]; cube[2][8] = temp[5][8];
				cube[5][6] = temp[3][6]; cube[5][7] = temp[3][7]; cube[5][8] = temp[3][8];
				cube[3][6] = temp[4][6]; cube[3][7] = temp[4][7]; cube[3][8] = temp[4][8];
				cube[4][6] = temp[2][6]; cube[4][7] = temp[2][7]; cube[4][8] = temp[2][8];
			}else if(oper.charAt(0) == 'F') {
				cube[4][8] = temp[0][6]; cube[4][5] = temp[0][7]; cube[4][2] = temp[0][8];
				cube[1][0] = temp[4][2]; cube[1][1] = temp[4][5]; cube[1][2] = temp[4][8];
				cube[5][6] = temp[1][0]; cube[5][3] = temp[1][1]; cube[5][0] = temp[1][2];
				cube[0][6] = temp[5][0]; cube[0][7] = temp[5][3]; cube[0][8] = temp[5][6];
			}else if(oper.charAt(0) == 'B') {
				cube[5][2] = temp[0][0]; cube[5][5] = temp[0][1]; cube[5][8] = temp[0][2];
				cube[1][8] = temp[5][2]; cube[1][7] = temp[5][5]; cube[1][6] = temp[5][8];
				cube[4][0] = temp[1][6]; cube[4][3] = temp[1][7]; cube[4][6] = temp[1][8];
				cube[0][2] = temp[4][0]; cube[0][1] = temp[4][3]; cube[0][0] = temp[4][6];
			}else if(oper.charAt(0) == 'L') {
				cube[0][0] = temp[2][0]; cube[0][3] = temp[2][3]; cube[0][6] = temp[2][6];
				cube[3][8] = temp[0][0]; cube[3][5] = temp[0][3]; cube[3][2] = temp[0][6];
				cube[1][6] = temp[3][2]; cube[1][3] = temp[3][5]; cube[1][0] = temp[3][8];
				cube[2][0] = temp[1][0]; cube[2][3] = temp[1][3]; cube[2][6] = temp[1][6];
			}else if(oper.charAt(0) == 'R') {
				cube[2][2] = temp[0][2]; cube[2][5] = temp[0][5]; cube[2][8] = temp[0][8];
				cube[1][2] = temp[2][2]; cube[1][5] = temp[2][5]; cube[1][8] = temp[2][8];
				cube[3][6] = temp[1][2]; cube[3][3] = temp[1][5]; cube[3][0] = temp[1][8];
				cube[0][8] = temp[3][0]; cube[0][5] = temp[3][3]; cube[0][2] = temp[3][6];
			}
		}
	}
	
	// 초기 cube의 각 면에 지정된 색을 칠해주는 메서드
	public static void init() {
		char color = '-';
		for(int k = 0; k &amp;lt; 6; k++) {
			if(k == 0) color = 'w';
			else if(k == 1) color = 'y';
			else if(k == 2) color = 'r';
			else if(k == 3) color = 'o';
			else if(k == 4) color = 'g';
			else if(k == 5) color = 'b';
			for(int i = 0; i &amp;lt; 9; i++) {
				cube[k][i] = color;
			}
		}
	}
	// cube 배열 복사본을 생성해 반환하는 메서드
	public static char[][] copy(){
		char[][] temp = new char[6][9];
		for(int k = 0; k &amp;lt; 6; k++) {
			for(int i = 0; i &amp;lt; 9; i++) {
				temp[k][i] = cube[k][i];
			}
		}
		return temp;
	}
	
	public static void printUp() {
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i &amp;lt; 3; i++) {
			sb.append(cube[0][i * 3]);
			sb.append(cube[0][i * 3 + 1]);
			sb.append(cube[0][i * 3 + 2]);
			if(i != 2) {
				sb.append(&quot;\n&quot;);
			}
		}
		System.out.println(sb.toString());
	}
	
	// test를 위해 cube의 모든 면을 출력하는 메서드
	public static void print() {
		String name = &quot;&quot;;
		for(int k = 0; k &amp;lt; 6; k++) {
			if(k == 0) name = &quot;윗면&quot;;
			else if(k == 1) name = &quot;아랫면&quot;;
			else if(k == 2) name = &quot;앞면&quot;;
			else if(k == 3) name = &quot;뒷면&quot;;
			else if(k == 4) name = &quot;왼쪽면&quot;;
			else if(k == 5) name = &quot;오른쪽면&quot;;
			System.out.println(name);
			System.out.println(Arrays.toString(cube[k]));
			System.out.println();
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithms</category>
      <category>5373 Java</category>
      <category>5373 자바</category>
      <category>백준 5373</category>
      <category>백준 시뮬레이션</category>
      <category>백준 큐빙</category>
      <category>큐빙 Java</category>
      <category>큐빙 자바</category>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/118</guid>
      <comments>https://sdesigner.tistory.com/118#entry118comment</comments>
      <pubDate>Sat, 26 Jun 2021 08:23:37 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] 15686번 치킨 배달 Java 풀이</title>
      <link>https://sdesigner.tistory.com/117</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1736&quot; data-origin-height=&quot;1632&quot; data-filename=&quot;스크린샷 2021-06-26 오전 7.43.41.png&quot; width=&quot;617&quot; height=&quot;580&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FjR03/btq8br3E5Jx/SPvfbbrF3iti7rBws5F5nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FjR03/btq8br3E5Jx/SPvfbbrF3iti7rBws5F5nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FjR03/btq8br3E5Jx/SPvfbbrF3iti7rBws5F5nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFjR03%2Fbtq8br3E5Jx%2FSPvfbbrF3iti7rBws5F5nk%2Fimg.png&quot; data-origin-width=&quot;1736&quot; data-origin-height=&quot;1632&quot; data-filename=&quot;스크린샷 2021-06-26 오전 7.43.41.png&quot; width=&quot;617&quot; height=&quot;580&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1736&quot; data-origin-height=&quot;1486&quot; data-filename=&quot;스크린샷 2021-06-26 오전 7.43.55.png&quot; width=&quot;631&quot; height=&quot;540&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZlRXd/btq8brigIiq/k0A2kUBsKVv3dnlncK4cpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZlRXd/btq8brigIiq/k0A2kUBsKVv3dnlncK4cpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZlRXd/btq8brigIiq/k0A2kUBsKVv3dnlncK4cpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZlRXd%2Fbtq8brigIiq%2Fk0A2kUBsKVv3dnlncK4cpK%2Fimg.png&quot; data-origin-width=&quot;1736&quot; data-origin-height=&quot;1486&quot; data-filename=&quot;스크린샷 2021-06-26 오전 7.43.55.png&quot; width=&quot;631&quot; height=&quot;540&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 처음 풀었을 때는 시간 초과를 받고, 풀이를 약간 변형해서 통과했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;첫 번째 풀이 DFS - 시간초과&lt;/h4&gt;
&lt;pre id=&quot;code_1624661482874&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public static void dfs(int cnt) {
		// 치킨집을 m개 오픈한 경우 도시의 치킨거리 계산
		if(cnt == m) {
			int cityDist = calculate();
			answer = Math.min(answer, cityDist);
		}
		
		// m개 미만 오픈한 경우 오픈
		for(int i = 0; i &amp;lt; n; i++) {
			for(int j = 0; j &amp;lt; n; j++) {
				if(board[i][j] == 2 &amp;amp;&amp;amp; !isOpened[i][j]) {
					// 오픈해서 dfs 호출 
					isOpened[i][j] = true;
					chickens.add(new Info(i, j, 2));
					dfs(cnt + 1);
					// 호출 후 원상복구
					isOpened[i][j] = false;
					chickens.remove(chickens.size() - 1);
				}
			}
		}
	} // end of dfs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 풀이에서는 전체 지도(board)의 0행 0열부터 차례대로 찾으며 열려있지 않은 치킨집을 오픈시킨다. 백트래킹 방식으로 동작하기 때문에 같은 조합의 치킨집을 오픈하더라도, 아래와 같은 케이스들이 모두 별개로 취급되어 치킨거리를 계산하게 된다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(1, 2), (3, 4), (4, 5)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;(1, 2), (4, 5), (3, 4)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;(4, 5), (1, 2), (3, 4)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;(3, 4), (1, 2), (4, 5)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;(4, 5), (3, 4), (1, 2)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;(3, 4), (4, 5), (1, 2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 (1, 2), (3, 4), (4, 5) 3개의 위치에 치킨집을 오픈한다고 했을 때, 위&amp;nbsp; 6가지 케이스들은 모두 같은 치킨거리를 갖게 되지만 모두 따로 계산되어 각각 치킨거리를 탐색하게 된다. 치킨집의 최대 갯수가 13개인데 위와 같이 자리를 모두 바꾼다면? 13! = 약 60억으로 시간초과가 날 수 밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문제를 두 번째 문제에서 스택을 활용해 해결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;두 번째 풀이 DFS - 성공&lt;/h4&gt;
&lt;pre id=&quot;code_1624661507714&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public static void dfs(int start, int cnt) {
		// 치킨집을 m개 오픈한 경우 도시의 치킨거리 계산
		if(cnt == m) {
			int cityDist = calculate();
			answer = Math.min(answer, cityDist);
		}
		
		// m개 미만 오픈한 경우 오픈
		for(int i = start; i &amp;lt; chickens.size(); i++) {
			Info now = chickens.get(i);
			// 오픈해서 dfs 호출
			selected.push(now);
			dfs(i + 1, cnt + 1);
			// 호출 후 원상복구
			selected.pop();
		}
	} // end of dfs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 치킨집의 위치를&amp;nbsp; 지도에서 꺼내지 않고, chickens라는 List에서 꺼내온다. 리스트에 미리 치킨집이 들어올 수 있는 위치들을 저장해놓고, 리스트의 인덱스를 dfs 메서드의 인자로 주고받으면서 어디부터 오픈할지를 저장해둔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, selected를 Stack으로 두면서 전체 경우의 수를 한 번씩만 탐색하도록 한다. 지도를 처음부터 선택하도록 하는 것이 아닌 인자를 하나 추가하고 다른 자료구조를 사용하는 방식으로 시간복잡도를 매우 개선할 뿐만 아니라 코드 라인 수도 줄이고 풀이도 훨씬 간결해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;두 번째 풀이 전체 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1624662448818&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;

public class Main {
	static int n, m, answer;
	static int[][] board;
	static List&amp;lt;Info&amp;gt; houses = new ArrayList&amp;lt;&amp;gt;();
	static List&amp;lt;Info&amp;gt; chickens = new ArrayList&amp;lt;&amp;gt;();
	static Stack&amp;lt;Info&amp;gt; selected = new Stack&amp;lt;&amp;gt;();
	
	
	public static void main(String[] args) throws Exception{
		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];
		answer = Integer.MAX_VALUE;
		
		for(int i = 0; i &amp;lt; n; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j = 0; j &amp;lt; n; j++) {
				board[i][j] = Integer.parseInt(st.nextToken());
				// 집이면 리스트에 추가해놓음
				if(board[i][j] == 1) {
					houses.add(new Info(i, j, 1));
				}else if(board[i][j] == 2) {
					chickens.add(new Info(i, j, 2));
				}
			}
		}
		dfs(0, 0);
		System.out.println(answer);
	}
	
	public static void dfs(int start, int cnt) {
		// 치킨집을 m개 오픈한 경우 도시의 치킨거리 계산
		if(cnt == m) {
			int cityDist = calculate();
			answer = Math.min(answer, cityDist);
		}
		
		// m개 미만 오픈한 경우 오픈
		for(int i = start; i &amp;lt; chickens.size(); i++) {
			Info now = chickens.get(i);
			// 오픈해서 dfs 호출
			selected.push(now);
			dfs(i + 1, cnt + 1);
			// 호출 후 원상복구
			selected.pop();
		}
	} // end of dfs
	
	public static int calculate() {
		int cityMinDist = 0;
		// 집을 하나씩 골라
		for(int i = 0; i &amp;lt; houses.size(); i++) {
			Info nowHouse = houses.get(i);
			int minDist = Integer.MAX_VALUE;
			// 치킨집마다 거리를 계산하고 최소 치킨거리 갱신 가능하면 갱신
			for(int j = 0; j &amp;lt; selected.size(); j++) {
				Info nowChicken = selected.get(j);
				// 현재 집과 치킨집 거리 계산
				int dist = Math.abs(nowHouse.row - nowChicken.row) 
						+ Math.abs(nowHouse.col - nowChicken.col);
				// 최소 치킨거리 갱신 가능하면 갱신
				minDist = Math.min(dist, minDist);
			}
			// 현재 집에서 가장 가까운 치킨거리를 도시 치킨거리에 반영
			cityMinDist += minDist;
		}
		return cityMinDist;
	}
	

}
class Info{
	int row, col;
	int type;
	public Info(int row, int col, int type) {
		this.row = row;
		this.col = col;
		this.type = type;
	}
	@Override
	public String toString() {
		return &quot;Info [row=&quot; + row + &quot;, col=&quot; + col + &quot;, type=&quot; + type + &quot;]&quot;;
	}
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithms</category>
      <category>15686 Java</category>
      <category>15686 자바</category>
      <category>백준 15686</category>
      <category>백준 치킨배달</category>
      <category>백준 치킨배달 Java</category>
      <category>백준 치킨배달 자바</category>
      <category>치킨배달 Java</category>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/117</guid>
      <comments>https://sdesigner.tistory.com/117#entry117comment</comments>
      <pubDate>Sat, 26 Jun 2021 08:11:15 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] 15684번 사다리 조작 Java 풀이</title>
      <link>https://sdesigner.tistory.com/116</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1256&quot; data-filename=&quot;스크린샷 2021-06-25 오후 6.01.22.png&quot; width=&quot;677&quot; height=&quot;605&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dr6jr/btq8atmIPuB/lFLxybGvB6UKHVHTV2wRH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dr6jr/btq8atmIPuB/lFLxybGvB6UKHVHTV2wRH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dr6jr/btq8atmIPuB/lFLxybGvB6UKHVHTV2wRH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDr6jr%2Fbtq8atmIPuB%2FlFLxybGvB6UKHVHTV2wRH1%2Fimg.png&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1256&quot; data-filename=&quot;스크린샷 2021-06-25 오후 6.01.22.png&quot; width=&quot;677&quot; height=&quot;605&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;1610&quot; data-filename=&quot;스크린샷 2021-06-25 오후 6.01.46.png&quot; width=&quot;695&quot; height=&quot;707&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs8vvC/btq75t3ig3k/OOkgVlRVCahGq18vqfZu0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs8vvC/btq75t3ig3k/OOkgVlRVCahGq18vqfZu0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs8vvC/btq75t3ig3k/OOkgVlRVCahGq18vqfZu0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs8vvC%2Fbtq75t3ig3k%2FOOkgVlRVCahGq18vqfZu0K%2Fimg.png&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;1610&quot; data-filename=&quot;스크린샷 2021-06-25 오후 6.01.46.png&quot; width=&quot;695&quot; height=&quot;707&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1456&quot; data-filename=&quot;스크린샷 2021-06-25 오후 6.01.59.png&quot; width=&quot;668&quot; height=&quot;648&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl4Y59/btq79WvZYvj/ikOGtK3aGkncKv8mObKg20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl4Y59/btq79WvZYvj/ikOGtK3aGkncKv8mObKg20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl4Y59/btq79WvZYvj/ikOGtK3aGkncKv8mObKg20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl4Y59%2Fbtq79WvZYvj%2FikOGtK3aGkncKv8mObKg20%2Fimg.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1456&quot; data-filename=&quot;스크린샷 2021-06-25 오후 6.01.59.png&quot; width=&quot;668&quot; height=&quot;648&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS로 구현하다가 막혀, 다른 분의 풀이 소스를 참고했다. DFS 백트래킹으로 최솟값을 찾는 문제를 접근하면 반드시 끝까지 탐색하면서 최솟값을 갱신할 수 있으면 갱신하는 방식으로만 풀이가 가능하다고 생각했다. 그런데 모든 문제에 적용할 수는 없겠지만, 이 문제에서는 DFS를 약간 변형하는 방법으로 효율적으로 풀이를 하는 방법이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고: &lt;a href=&quot;https://leveloper.tistory.com/96&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leveloper.tistory.com/96&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;풀이 구성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;void dfs(int x, int count): 가로선을 놓은 개수(count), 가로선을 놓을 지 말지 탐색할 높이(x)를 기준으로 재귀적으로 가로선을 놓고 다음 함수를 호출한 뒤, 다시 가로선을 제거하는 메서드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;boolean check(): 모든 세로선이 주어진 조건을 만족하는지 판별해주는 boolean 반환 메서드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;int[][] map: 사다리 정보 가진 2차원 배열, 1이면 오른쪽 방향 사다리를 둔 상태이고 2이면 왼쪽 방향으로 사다리를 둔 상태로 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;boolean finish: 현재 map을 기반으로 주어진 조건 만족하는지를 나타내는 플래그 변수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;전체 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1624660920611&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.util.StringTokenizer; 
public class Main { 
	private static int n, m, h, answer; 
	private static int[][] map; 
	private static boolean finish = false; 
	
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
		StringTokenizer st = new StringTokenizer(br.readLine()); 
		n = Integer.parseInt(st.nextToken()); 
		m = Integer.parseInt(st.nextToken()); 
		h = Integer.parseInt(st.nextToken()); 
		map = new int[h + 1][n + 1]; 
		
		for (int i = 0; i &amp;lt; m; i++) { 
			int x, y;
			st = new StringTokenizer(br.readLine()); 
			x = Integer.parseInt(st.nextToken()); 
			y = Integer.parseInt(st.nextToken());
			// 1이면 오른쪽 방향 사다리, 2이면 왼쪽 방향 사다리
			map[x][y] = 1; 
			map[x][y + 1] = 2;
		} 
		
		// 사다리를 놓아보고 성공한다면 바로 break, 안되면 3번까지
		for (int i = 0; i &amp;lt;= 3; i++) { 
			answer = i; 
			dfs(1, 0); 
			if (finish) break;
		} 
		
		System.out.println((finish) ? answer : -1);
	} 
	
	private static void dfs(int x, int count) {
		// 답을 찾았다면 더이상 연산하지 않음
		if (finish) return; 
		
		// 0 ~ 3번째 사다리를 놓은 상태에서
		if (answer == count) { 
			// 모든 세로선이 조건을 만족한다면 종료
			if (check()) finish = true; 
			return;
		} 
		// 높이 depth를 1부터 h까지
		for (int i = x; i &amp;lt; h + 1; i++) {
			// 1번부터 마지막 전 세로선까지
			for (int j = 1; j &amp;lt; n; j++) {
				// 우측으로 가로선이 존재하지 않으면
				if (map[i][j] == 0 &amp;amp;&amp;amp; map[i][j + 1] == 0) {
					// 가로선을 놓는다
					map[i][j] = 1; 
					map[i][j + 1] = 2;
					// 가로선을 놓은 상태에서 dfs 호출
					dfs(i, count + 1); 
					// 다시 가로선 제거
					map[i][j] = map[i][j + 1] = 0;
				}
			}
		} 
	} 
	
	// 모든 세로선이 조건을 만족하는지 판별해주는 boolean 반환 메서드 
	private static boolean check() { 
		// i: 세로선
		// y: 움직이는 위치에서의 column
		for (int i = 1; i &amp;lt;= n; i++) { 
			int x = 1, y = i;
			// j: 높이
			// x: h번 하강하는 과정에서의 depth
			for (int j = 0; j &amp;lt; h; j++) {
				// 1이면 오른쪽 이동
				if (map[x][y] == 1) y++;
				// 2이면 왼쪽 이동
				else if (map[x][y] == 2) y--;
				// 1만큼 내려감
				x++; 
			} 
			// 출발 세로선 인덱스와 도착한 세로선 인덱스가 다르면 false
			if (y != i) return false; 
		} 
		// 모든 세로선의 출발 세로선 인덱스와 도착한 세로선 인덱스가 같은 경우 true
		return true; 
	} 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithms</category>
      <category>15684 Java</category>
      <category>15684 자바</category>
      <category>백준 15684</category>
      <category>백준 백트래킹</category>
      <category>백준 재귀</category>
      <category>백트래킹</category>
      <category>사다리조작 자바</category>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/116</guid>
      <comments>https://sdesigner.tistory.com/116#entry116comment</comments>
      <pubDate>Sat, 26 Jun 2021 07:40:18 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] 15683번 감시 Java 풀이</title>
      <link>https://sdesigner.tistory.com/115</link>
      <description>&lt;pre id=&quot;code_1624079646568&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	static int n, m, blindSpot = 0;
	static int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1};
	static List&amp;lt;int[]&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();
	static int[][] stat= {
			{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1},
			{1, 0, 1, 0}, {0, 1, 0, 1}, {1, 1, 0, 0}, {0, 1, 1, 0},
			{0, 0, 1, 1}, {1, 0, 0, 1}, {1, 1, 1, 0}, {0, 1, 1, 1},
			{1, 0, 1, 1}, {1, 1, 0, 1}, {1, 1, 1, 1}
	};
	
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());
		
		int[][] room = new int[n + 1][m + 1];
		
		for(int i = 1; i &amp;lt;= n; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j = 1; j &amp;lt;= m; j++) {
				room[i][j] = Integer.parseInt(st.nextToken());
				
				if(room[i][j] == 0) blindSpot++;
				if(0 &amp;lt; room[i][j] &amp;amp;&amp;amp; room[i][j] &amp;lt; 6) list.add(new int[] {i, j});
			}
		}
		
		bfs(room, blindSpot);
		System.out.println(blindSpot);
		
	}
	// 모든 cctv의 동작 조합을 시도
	static void bfs(int[][] room, int blindSpot) {
		Queue&amp;lt;Info&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
		q.add(new Info(blindSpot, room));
		
		for(int i = 0; i &amp;lt; list.size(); i++) {
			int qLen = q.size();
			
			for(int t = 0; t &amp;lt; qLen; t++) {
				Info m = q.poll();
				int bs = m.blindSpot;
				int row = list.get(i)[0];
				int col = list.get(i)[1];
				
				if(room[row][col] == 1) {
					q.add(cctv(m.room, row, col, bs, stat[0]));
					q.add(cctv(m.room, row, col, bs, stat[1]));
					q.add(cctv(m.room, row, col, bs, stat[2]));
					q.add(cctv(m.room, row, col, bs, stat[3]));
				}
				if(room[row][col] == 2) {
					q.add(cctv(m.room, row, col, bs, stat[4]));
					q.add(cctv(m.room, row, col, bs, stat[5]));
				}
				if(room[row][col] == 3) {
					q.add(cctv(m.room, row, col, bs, stat[6]));
					q.add(cctv(m.room, row, col, bs, stat[7]));
					q.add(cctv(m.room, row, col, bs, stat[8]));
					q.add(cctv(m.room, row, col, bs, stat[9]));
				}
				if(room[row][col] == 4) {
					q.add(cctv(m.room, row, col, bs, stat[10]));
					q.add(cctv(m.room, row, col, bs, stat[11]));
					q.add(cctv(m.room, row, col, bs, stat[12]));
					q.add(cctv(m.room, row, col, bs, stat[13]));
				}
				if(room[row][col] == 5) {
					q.add(cctv(m.room, row, col, bs, stat[14]));
				}
			}
		}
	}
	
	// cctv를 동작시키고 결과와 blindSpot 개수를 세어 반환
	static Info cctv(int[][] room, int row, int col, int num, int[] status) {
		int[][] result = copy(room);
		
		// 비추는 방향마다 벽을 만나거나 방을 벗어날 때까지 비추도록 함
		for(int i = 0; i &amp;lt; 4; i++) {
			// 현재 방향을 비추지 않으면 continue
			if(status[i] == 0) continue;
			int nxtRow = row;
			int nxtCol = col;
			
			while(true) {
				nxtRow = nxtRow + dx[i];
				nxtCol = nxtCol + dy[i];
				
				// 다음 위치가 room 내부를 벗어나거나 벽이라면 이동할 수 없음
				if(nxtRow &amp;lt; 1 || nxtRow &amp;gt; n || nxtCol &amp;lt; 1 || nxtCol &amp;gt; m) break;
				if(result[nxtRow][nxtCol] == 6) break;
				
				if(result[nxtRow][nxtCol] == 0) {
					result[nxtRow][nxtCol] = 8;
					num--;
				}
			}
		}
		
		if(blindSpot &amp;gt; num) blindSpot = num;
		return new Info(num, result);
	}
	
	static int[][] copy(int[][] room){
		int[][] result = new int[n + 1][m + 1];
		for(int i = 0; i&amp;lt;= n; i++) {
			System.arraycopy(room[i], 0, result[i], 0, m + 1);
		}
		return result;
	}
}

class Info{
	int blindSpot;
	int[][] room;
	
	public Info(int blindSpot, int[][] room) {
		this.blindSpot = blindSpot;
		this.room = room;
	}
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/115</guid>
      <comments>https://sdesigner.tistory.com/115#entry115comment</comments>
      <pubDate>Sat, 19 Jun 2021 14:14:10 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] 14891번 톱니바퀴 Java 풀이</title>
      <link>https://sdesigner.tistory.com/114</link>
      <description>&lt;pre id=&quot;code_1624079600816&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static int[][] circles = new int[4][8];
	static int K, result;
	static int[] isRotate;
	
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		for(int i = 0; i &amp;lt; 4; i++) {
			String[] input = br.readLine().split(&quot;&quot;);
			for(int j = 0; j &amp;lt; 8; j++) {
				circles[i][j] = Integer.parseInt(input[j]);
			}
		}
		
		K = Integer.parseInt(br.readLine());
		StringTokenizer st;
		for(int k = 0; k &amp;lt; K; k++) {
			st = new StringTokenizer(br.readLine());
			int circleIndex = Integer.parseInt(st.nextToken());
			int direction = Integer.parseInt(st.nextToken());
			isRotate = new int[4];
			
			check(circleIndex - 1, direction);
			rotate();
		}
		System.out.println(countScore());
	}
	
	static int countScore() {
		int result = 0;
		for(int i = 0; i &amp;lt; 4; i++) {
			if(circles[i][0] == 1) {
				result += Math.pow(2, i);
			}
		}
		return result;
	}
	
	static void check(int circleNum, int dir) {
		isRotate[circleNum] = dir;
		
		int prev = circleNum - 1;
		int next = circleNum + 1;
		
		if(prev &amp;gt;= 0 &amp;amp;&amp;amp; isRotate[prev] == 0) {
			// 왼쪽 바퀴 검사
			if(circles[prev][2] != circles[circleNum][6]) {
				check(prev, dir * -1);
			}
		}
		
		if(next &amp;lt;= 3 &amp;amp;&amp;amp; isRotate[next] == 0) {
			// 오른쪽 바퀴 검사 
			if(circles[circleNum][2] != circles[next][6]) {
				check(next, dir * -1);
			}
		}
	}
	
	static void rotate() {
		for(int i = 0; i &amp;lt; 4; i++) {
			if(isRotate[i] != 0) {
				int[] result = new int[8];
				
				for(int j = 0; j &amp;lt; 8; j++) {
					int resultIndex = j + isRotate[i];
					
					if(resultIndex == -1) {
						resultIndex = 7;
					}else if(resultIndex == 8) {
						resultIndex = 0;
					}
					
					result[resultIndex] = circles[i][j];
				}
				circles[i] = result;
			}
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/114</guid>
      <comments>https://sdesigner.tistory.com/114#entry114comment</comments>
      <pubDate>Sat, 19 Jun 2021 14:13:24 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] 14890번 경사로 Java 풀이</title>
      <link>https://sdesigner.tistory.com/113</link>
      <description>&lt;pre id=&quot;code_1624079552320&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static int N, L, answer;
	static int[][] board;
	static boolean[][] isPlaced;
	
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		L = Integer.parseInt(st.nextToken());
		
		board = new int[N][N];
		isPlaced = new boolean[N][N];
		
		for(int i = 0; i &amp;lt; N; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j = 0; j &amp;lt; N; j++) {
				board[i][j] = Integer.parseInt(st.nextToken());
			}
		}
		
		// 행 기준 검사
		for(int i = 0; i &amp;lt; N; i++) {
			boolean isPossible = true;
			for(int j = 0; j &amp;lt; N - 1; j++) {
				// 경사가 1 차이나는 지점을 만나면 
				if(Math.abs(board[i][j] - board[i][j + 1]) == 1) {
					// 좌상향 경사로인 경우
					// 경사로를 놓을 수 있는 길이가 부족하거나, 
					if(board[i][j] &amp;gt; board[i][j + 1]) {
						if(j + L &amp;gt; N - 1) {
							isPossible = false;
							continue;
						}
						// 그 길이의 블록에 이미 놓아진 경사로가 이미 있거나, 높이가 1 낮은 블록들이 아니라면 불가
						for(int k = 1; k &amp;lt;= L; k++) {
							if(isPlaced[i][j + k] || board[i][j + k] + 1 != board[i][j]) {
								isPossible = false;
								break;
							}
						}
						if(isPossible) {
							for(int k = 1; k &amp;lt;= L; k++) {
								isPlaced[i][j + k] = true;
							}
						}
					}else {	// 우상향 경사로인 경우
						if(j - L + 1 &amp;lt; 0) {
							isPossible = false;
							continue;
						}
						for(int k = 0; k &amp;lt; L; k++) {
							if(isPlaced[i][j - k] || board[i][j - k] + 1 != board[i][j + 1]) {
								isPossible = false;
								break;
							}
						}
						if(isPossible) {
							for(int k = 0; k &amp;lt; L; k++) {
								isPlaced[i][j - k] = true;
							}
						}
					}
				}else if(Math.abs(board[i][j] - board[i][j + 1]) &amp;gt; 1) {
					isPossible = false;
				}
			}
			// 경사로를 놓을 수 있거나, 모두 높이가 같다면 answer 증가
			if(isPossible) {
				answer++;
			}
		}
		
		// 경사로 초기화
		isPlaced = new boolean[N][N];
		
		
		// 열 기준 검사
		for(int j = 0; j &amp;lt; N; j++) {
			boolean isPossible = true;
			for(int i = 0; i &amp;lt; N - 1; i++) {
				// 경사가 1 차이나는 지점을 만나면 
				if(Math.abs(board[i][j] - board[i + 1][j]) == 1) {
					// 경사로를 놓을 수 있는 길이가 부족하거나, 
					if(board[i][j] &amp;gt; board[i + 1][j]) {
						if(i + L &amp;gt; N - 1) {
							isPossible = false;
							continue;
						}
						// 그 길이의 블록에 이미 놓아진 경사로가 이미 있거나, 높이가 1 낮은 블록들이 아니라면 불가
						for(int k = 1; k &amp;lt;= L; k++) {
							if(isPlaced[i + k][j] || board[i + k][j] + 1 != board[i][j]) {
								isPossible = false;
								break;
							}
						}
						if(isPossible) {
							for(int k = 1; k &amp;lt;= L; k++) {
								isPlaced[i + k][j] = true;
							}
						}
					}else {	
						if(i - L + 1 &amp;lt; 0) {
							isPossible = false;
							continue;
						}
						for(int k = 0; k &amp;lt; L; k++) {
							if(isPlaced[i - k][j] || board[i - k][j] + 1 != board[i + 1][j]) {
								isPossible = false;
								break;
							}
						}
						if(isPossible) {
							for(int k = 0; k &amp;lt; L; k++) {
								isPlaced[i - k][j] = true;
							}
						}
					}
				}else if(Math.abs(board[i][j] - board[i + 1][j]) &amp;gt; 1) {
					isPossible = false;
				}
			}
			// 경사로를 놓을 수 있거나, 모두 높이가 같다면 answer 증가
			if(isPossible) {
				answer++;
			}
		}
		System.out.println(answer);
	} // end of main
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>SDev</author>
      <guid isPermaLink="true">https://sdesigner.tistory.com/113</guid>
      <comments>https://sdesigner.tistory.com/113#entry113comment</comments>
      <pubDate>Sat, 19 Jun 2021 14:12:36 +0900</pubDate>
    </item>
  </channel>
</rss>