문제 설명


셔틀버스

카카오에서는 무료 셔틀버스를 운행하기 때문에 판교역에서 편하게 사무실로 올 수 있다. 카카오의 직원은 서로를 '크루'라고 부르는데, 아침마다 많은 크루들이 이 셔틀을 이용하여 출근한다.

이 문제에서는 편의를 위해 셔틀은 다음과 같은 규칙으로 운행한다고 가정하자.

  • 셔틀은 09:00부터 총 n회 t분 간격으로 역에 도착하며, 하나의 셔틀에는 최대 m명의 승객이 탈 수 있다.
  • 셔틀은 도착했을 때 도착한 순간에 대기열에 선 크루까지 포함해서 대기 순서대로 태우고 바로 출발한다. 예를 들어 09:00에 도착한 셔틀은 자리가 있다면 09:00에 줄을 선 크루도 탈 수 있다.

일찍 나와서 셔틀을 기다리는 것이 귀찮았던 콘은, 일주일간의 집요한 관찰 끝에 어떤 크루가 몇 시에 셔틀 대기열에 도착하는지 알아냈다. 콘이 셔틀을 타고 사무실로 갈 수 있는 도착 시각 중 제일 늦은 시각을 구하여라.

단, 콘은 게으르기 때문에 같은 시각에 도착한 크루 중 대기열에서 제일 뒤에 선다. 또한, 모든 크루는 잠을 자야 하므로 23:59에 집에 돌아간다. 따라서 어떤 크루도 다음날 셔틀을 타는 일은 없다.

입력 형식

셔틀 운행 횟수 n, 셔틀 운행 간격 t, 한 셔틀에 탈 수 있는 최대 크루 수 m, 크루가 대기열에 도착하는 시각을 모은 배열 timetable이 입력으로 주어진다.

  • 0 < n ≦ 10
  • 0 < t ≦ 60
  • 0 < m ≦ 45
  • timetable은 최소 길이 1이고 최대 길이 2000인 배열로, 하루 동안 크루가 대기열에 도착하는 시각이 HH:MM 형식으로 이루어져 있다.
  • 크루의 도착 시각 HH:MM은 00:01에서 23:59 사이이다.

출력 형식

콘이 무사히 셔틀을 타고 사무실로 갈 수 있는 제일 늦은 도착 시각을 출력한다. 도착 시각은 HH:MM 형식이며, 00:00에서 23:59 사이의 값이 될 수 있다.

입출력 예제

ntmtimetableanswer

1 1 5 ["08:00", "08:01", "08:02", "08:03"] "09:00"
2 10 2 ["09:10", "09:09", "08:00"] "09:09"
2 1 2 ["09:00", "09:00", "09:00", "09:00"] "08:59"
1 1 5 ["00:01", "00:01", "00:01", "00:01", "00:01"] "00:00"
1 1 1 ["23:59"] "09:00"
10 60 45 ["23:59","23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59"] "18:00"

 

 

 

접근 방법


가장 마지막에 타기 위해서는 가장 마지막 버스를 타면 됩니다. 이 때 2가지 경우가 있습니다.

1. 마지막 버스에 빈자리가 있는 경우

2. 마지막 버스에 빈자리가 없는 경우

 

1번의 경우 마지막 버스의 출발시간이 정답이 될 것입니다.

2번의 경우는 마지막 버스에 마지막으로 올라탄 사람보다 1분 일찍 도착한다면 마지막 버스를 탈 수 있게 될 것입니다.

 

문제 풀이

 

1. 위의 결과를 도출하기 위해 [버스에 타고있는 인원, 버스의 출발시간, 버스에 마지막으로 탄 사람의 도착시간] 3가지의 정보가 필요합니다. 이 3가지의 정보를 담고 있는 구조체를 가진 배열을 초기화 합니다.

2. 또한 timetable이 string의 형식이므로 계산을 편히 하기 위해 int로 바꾸어줄 필요가 있습니다. int형으로 바꾸어 주었다면 사람들을 도착한 순서대로 정렬을 시킵니다.  

typedef struct info{
    int cnt, start, last;
};

vector<int> table; //timetable을 int로 변환
vector<info> busTable; //버스 배열

void init(vector<string> &timetable, int n, int t, int m){
    
    //time table을 int로 변환하여 table에 입력
    for(int i=0;i<timetable.size();i++){
        string t = timetable[i];
        int h = atoi(t.substr(0,2).c_str()); 
        int m = atoi(t.substr(3,2).c_str()); 
        table.push_back(h*60 + m);
    }
    //도착한 순서대로 정렬(오름차순)
    sort(table.begin(), table.end());
    
    //버스의 정보를 담고 있는 배열 초기화
    int start = 9*60; //출발시간이 09:00이므로
    for(int i=0;i<n;i++){ //버스는 n번 운행 됨
        busTable.push_back({0, start, 0}); //탑승한 인원, 출발시간, 마지막에 탑승한 사람의 도착시간 
        start += t; //t분 간격으로 운행
    }
}

 

이러한 초기화 과정의 끝났다면 모든 승객을 버스에 배치 시켜 봅니다.

 

 사람의 도착시간이 버스의 출발시간 보다 빠르고 버스에 빈 자리가 있을 때에만 버스에 탑승이 가능합니다.

반대의 경우는 탑승 불가능 하며 다음 버스에 배치를 해야합니다.

string solve(int m, int n){
    
    int busNum = 0;
    string ans = "";
    
    for(int i=0;i<table.size();i++){
        //버스에 탈 수 있는 경우, 수용가능하며 시간이 맞을 때
        if(busTable[busNum].cnt < m && table[i] <= busTable[busNum].start){
            busTable[busNum].cnt++;
            busTable[busNum].last = table[i];
        } // 시간이 밀리거나 버스가 꽉 찾다면
        else{
            busNum++; //다음 버스
            i--;  //현재 인원이 아직 처리가 안됬기 때문임
        }
        
        //모든 버스가 운행 종료
        if(busNum >= n)
            break;
    }
    
    //마지막 버스
    info bus = busTable.back();
    //버스에 빈 자리가 있다면 버스의 출발시간, 아니라면 버스에 탑승한 마지막 인원 보다 1분 일찍
    return ans = (bus.cnt < m) ? intToStr(bus.start) : intToStr(bus.last - 1);
}

 

 

소스 코드


#include <string>
#include <vector>
#include <algorithm>

using namespace std;

typedef struct info{
    int cnt, start, last;
};

vector<int> table;
vector<info> busTable;

void init(vector<string> &timetable, int n, int t, int m){
    
    for(int i=0;i<timetable.size();i++){
        string t = timetable[i];
        int h = atoi(t.substr(0,2).c_str());
        int m = atoi(t.substr(3,2).c_str());
        table.push_back(h*60 + m);
    }
    sort(table.begin(), table.end());
    
    int start = 9*60;
    for(int i=0;i<n;i++){
        busTable.push_back({0, start, 0});
        start += t;
    }
}

string intToStr(int time){
    
    int h = time/60;
    int m = time%60;
    
    string H = to_string(h);
    string M = to_string(m);
    
    H = (H.size() == 1) ? "0" + H : H;
    M = (M.size() == 1) ? "0" + M : M;
    
    return H + ":" + M;
}

string solve(int m, int n){
    
    int busNum = 0;
    string ans = "";
    
    for(int i=0;i<table.size();i++){
        //버스에 탈 수 있는 경우, 수용가능하며 시간이 맞을 때
        if(busTable[busNum].cnt < m && table[i] <= busTable[busNum].start){
            busTable[busNum].cnt++;
            busTable[busNum].last = table[i];
        } // 시간이 밀리거나 버스가 꽉 찾다면
        else{
            busNum++;
            i--;
        }
        
        if(busNum >= n)
            break;
    }
    
    info bus = busTable.back();
    return ans = (bus.cnt < m) ? intToStr(bus.start) : intToStr(bus.last - 1);
}

string solution(int n, int t, int m, vector<string> timetable) {
    string answer = "";
    init(timetable,n,t,m);
    
    return answer = solve(m, n);
}

 

문제 설명


매칭 점수

프렌즈 대학교 조교였던 제이지는 허드렛일만 시키는 네오 학과장님의 마수에서 벗어나, 카카오에 입사하게 되었다.
평소에 관심있어하던 검색에 마침 결원이 발생하여, 검색개발팀에 편입될 수 있었고, 대망의 첫 프로젝트를 맡게 되었다.
그 프로젝트는 검색어에 가장 잘 맞는 웹페이지를 보여주기 위해 아래와 같은 규칙으로 검색어에 대한 웹페이지의 매칭점수를 계산 하는 것이었다.

  • 한 웹페이지에 대해서 기본점수, 외부 링크 수, 링크점수, 그리고 매칭점수를 구할 수 있다.
  • 한 웹페이지의 기본점수는 해당 웹페이지의 텍스트 중, 검색어가 등장하는 횟수이다. (대소문자 무시)
  • 한 웹페이지의 외부 링크 수는 해당 웹페이지에서 다른 외부 페이지로 연결된 링크의 개수이다.
  • 한 웹페이지의 링크점수는 해당 웹페이지로 링크가 걸린 다른 웹페이지의 기본점수 ÷ 외부 링크 수의 총합이다.
  • 한 웹페이지의 매칭점수는 기본점수와 링크점수의 합으로 계산한다.

예를 들어, 다음과 같이 A, B, C 세 개의 웹페이지가 있고, 검색어가 hi라고 하자.

이때 A 웹페이지의 매칭점수는 다음과 같이 계산할 수 있다.

  • 기본 점수는 각 웹페이지에서 hi가 등장한 횟수이다.
    • A,B,C 웹페이지의 기본점수는 각각 1점, 4점, 9점이다.
  • 외부 링크수는 다른 웹페이지로 링크가 걸린 개수이다.
    • A,B,C 웹페이지의 외부 링크 수는 각각 1점, 2점, 3점이다.
  • A 웹페이지로 링크가 걸린 페이지는 B와 C가 있다.
    • A 웹페이지의 링크점수는 B의 링크점수 2점(4 ÷ 2)과 C의 링크점수 3점(9 ÷ 3)을 더한 5점이 된다.
  • 그러므로, A 웹페이지의 매칭점수는 기본점수 1점 + 링크점수 5점 = 6점이 된다.

검색어 word와 웹페이지의 HTML 목록인 pages가 주어졌을 때, 매칭점수가 가장 높은 웹페이지의 index를 구하라. 만약 그런 웹페이지가 여러 개라면 그중 번호가 가장 작은 것을 구하라.

제한사항

  • pages는 HTML 형식의 웹페이지가 문자열 형태로 들어있는 배열이고, 길이는 1 이상 20 이하이다.
  • 한 웹페이지 문자열의 길이는 1 이상 1,500 이하이다.
  • 웹페이지의 index는 pages 배열의 index와 같으며 0부터 시작한다.
  • 한 웹페이지의 url은 HTML의 <head> 태그 내에 <meta> 태그의 값으로 주어진다.
  • 한 웹페이지에서 모든 외부 링크는 <a href=https://careers.kakao.com/index>의 형태를 가진다.
    • <a> 내에 다른 attribute가 주어지는 경우는 없으며 항상 href로 연결할 사이트의 url만 포함된다.
    • 위의 경우에서 해당 웹페이지는 https://careers.kakao.com/index 로 외부링크를 가지고 있다고 볼 수 있다.
  • 모든 url은 https:// 로만 시작한다.
  • 검색어 word는 하나의 영어 단어로만 주어지며 알파벳 소문자와 대문자로만 이루어져 있다.
  • word의 길이는 1 이상 12 이하이다.
  • 검색어를 찾을 때, 대소문자 구분은 무시하고 찾는다.
    • 예를들어 검색어가 blind일 때, HTML 내에 Blind라는 단어가 있거나, BLIND라는 단어가 있으면 두 경우 모두 해당된다.
  • 검색어는 단어 단위로 비교하며, 단어와 완전히 일치하는 경우에만 기본 점수에 반영한다.
    • 단어는 알파벳을 제외한 다른 모든 문자로 구분한다.
    • 예를들어 검색어가 aba 일 때, abab abababa는 단어 단위로 일치하는게 없으니, 기본 점수는 0점이 된다.
    • 만약 검색어가 aba 라면, aba@aba aba는 단어 단위로 세개가 일치하므로, 기본 점수는 3점이다.
  • 결과를 돌려줄때, 동일한 매칭점수를 가진 웹페이지가 여러 개라면 그중 index 번호가 가장 작은 것를 리턴한다
    • 즉, 웹페이지가 세개이고, 각각 매칭점수가 3,1,3 이라면 제일 적은 index 번호인 0을 리턴하면 된다.

 

접근 방법


문제를 해결하기 위해 크게 5가지 방법으로 나눌 수 있습니다.

 

1. 대문자를 모두 소문자로 전처리하기

2. 자신의 페이지 이름 파악하기

3. 페이지의 기본 점수 구하기

4. 자신의 페이지를 A, 외부로 나가는 링크를 B라 한다면 A에서 외부로 나가는 링크 B를 저장하고, B는 자신으로 들어오는 링크 A를 저장하기

5. 점수 구하기

 

일단 위의 과정을 설명하기 이전에 문제를 해결하기 위해 전역변수로 사용한 4개의 HashMap에 대해 설명하겠습니다.

1. map<int, string> name;  =>  name[페이지index] = "페이지 주소"
2. map<string, int> score;  =>  score[페이지 주소] = 기본 점수
3. map<string, vector<string>> outdegree; => outdegree["페이지 주소"] = {외부로 나가는 링크들}
4. map<string, vector<string>> indegree;  => indegree["페이지 주소"] = {자신으로 들어오는 외부 링크들}

 

 

1. 대문자를 모두 소문자로 전처리하기

 

아스키 코드 표를 사용하여 어렵지 않게 소문자로 변환할 수 있습니다.

void toSmall(string &page){
        
    for(int j=0;j<page.size();j++)
        if(65 <= int(page[j]) && int(page[j]) <= 90)
            page[j] = char(int(page[j]) + 32);       
}

 

2. 자신의 페이지 이름 파악하기

 

 string 헤더의 find함수를 적절히 사용하여 구할 수 있었습니다. 자신의 페이지 주소 뿐만 아니라 용도에 맞게 어떠한 페이지의 주소라도 파악할 수 있도록 pattern이라는 매개변수를 추가하였습니다.

만약 자신의 페이지 주소를 파악하기 위해서는 pattern = "<meta property=\"og:url\" content="가 될 것이며

외부로 링크의 페이지 주소를 파악하기 위해서는  pattern = "<a href=" 가 될 것입니다. 

(참고로 문자열 안에 "를 사용하려면 \를 붙여 사용할 수 있습니다.)

//string myNamePattern = "<meta property=\"og:url\" content=";
// string outLinkPattern = "<a href=";
string getLinks(string &page, string pattern, int &idx){
    
    string url = "";
    idx = page.find(pattern, idx);
    
    if(idx == string::npos) return url;
    else idx += pattern.size();
    
    while(page[++idx] != '"')
        url += page[idx];
    
    return url;
}

 이 함수는 찾아낸 페이지의 주소의 문자열을 반환하며, idx를 참조로 받아 동시에 페이지 주소가 끝나는 지점의 index로 갱신됩니다.

 

 

3. 기본점수 구하기

 

기본점수는 페이지 문서 내에서 해당 단어가 몇번 등장하는지 찾을 수 있습니다. 단어의 앞뒤에 영어 철자가 존재하면 안된다는 규칙이 있어 단어를 찾아낸 뒤에 단어의 시작 지점보다 한 칸 앞과 단어의 끝 지점의 한 칸 뒤를 모두 확인해야 합니다. 이 때 cnt는 페이지에서 찾은 word의 수 입니다.

int getScore(string &word, string &page){
    
    int idx = page.find(word);
    int cnt = 0;
    
    while(page.find(word, idx) != string::npos){ //단어를 찾을 수 있는 동안에
        
        bool isWord = true;
        idx = page.find(word, idx);
        
        //단어의 앞 부분 확인
        if(0 <= idx - 1 && idx - 1 < page.size() && 'a' <= page[idx - 1] && page[idx - 1] <= 'z')    
            isWord = false;
        //단어의 뒷 부분 확인
        if(0 <= idx + word.size() && idx + word.size() < page.size() && 'a' <= page[idx + word.size()] && page[idx + word.size()] <= 'z')    
            isWord = false;
        if(isWord)
            cnt++;
        idx += word.size();
    }
    return cnt;
}

 

 

4. 자신의 페이지를 A, 외부로 나가는 링크를 B라 한다면 A에서 외부로 나가는 링크 B를 저장하고, B는 자신으로 들어오는 링크 A를 저장하기

 

2번에서 설명한 getLinks 함수를 사용하여 while문으로 문서의 끝까지 외부로 나가는 링크가 있는지 탐색을 하여 hashmap인 indegree와 outdegree에 등록합니다.

pos = 0;
while(pos != string::npos){

	string link = getLinks(page, outLinkPattern, pos);
	if(link.size() == 0)
		break;

	outdegree[myName].push_back(link);
	indegree[link].push_back(myName);
}

 

5. 점수 구하기

 

이제 점수를 구하기 위한 모든 정보를 저장했습니다. 매칭 점수는 아래의 수식으로 구할 수 있습니다.

매칭 점수 = 자신의 기본점수 + (외부로 나가는 링크들의 '링크 점수')

링크 점수 = (링크의 기본점수/링크의 외부로 나가는 링크)

(참고로 여기서 자료형을 float을 사용하면 통과하지 못하는 테스트 케이스가 있었습니다.)

double getMatchScore(int idx){
    
    string myName = name[idx];
    
    double baseScore = double(score[myName]);
    
    double linkScore = 0;
    vector<string> inLinks = indegree[myName];
    for(int i=0;i<inLinks.size();i++){
        string link = inLinks[i];
        linkScore += (double(score[link]) / double(outdegree[link].size()));
    }
    return baseScore + linkScore;
}

 

 

소스 코드


#include <string>
#include <vector>
#include <map>

using namespace std;

map<int, string> name;
map<string, int> score;
map<string, vector<string>> outdegree;
map<string, vector<string>> indegree;

void toSmall(string &page){
        
    for(int j=0;j<page.size();j++)
        if(65 <= int(page[j]) && int(page[j]) <= 90)
            page[j] = char(int(page[j]) + 32);       
}

string getLinks(string &page, string pattern, int &idx){
    
    string url = "";
    idx = page.find(pattern, idx);
    
    if(idx == string::npos) return url;
    else idx += pattern.size();
    
    while(page[++idx] != '"')
        url += page[idx];
    
    return url;
}

int getScore(string &word, string &page){
    
    int idx = page.find(word);
    int cnt = 0;
    
    while(page.find(word, idx) != string::npos){
        
        bool isWord = true;
        idx = page.find(word, idx);
        
        if(0 <= idx - 1 && idx - 1 < page.size() && 'a' <= page[idx - 1] && page[idx - 1] <= 'z')    
            isWord = false;
        if(0 <= idx + word.size() && idx + word.size() < page.size() && 'a' <= page[idx + word.size()] && page[idx + word.size()] <= 'z')    
            isWord = false;
        if(isWord)
            cnt++;
        idx += word.size();
    }
    return cnt;
}
    
void processing(string &word, string &page, int idx){
    
    string myNamePattern = "<meta property=\"og:url\" content=";
    string outLinkPattern = "<a href=";
    
    int pos = 0;
    string myName = getLinks(page, myNamePattern, pos); //함수 내부에 참조연산자를 사용하여 pos가 변할 수 있음
    name.insert({idx, myName});
    
    int cnt = getScore(word, page);
    score.insert({myName, cnt});
    
    pos = 0;
    while(pos != string::npos){
        
        string link = getLinks(page, outLinkPattern, pos);
        if(link.size() == 0)
            break;
        
        outdegree[myName].push_back(link);
        indegree[link].push_back(myName);
    }
}

double getMatchScore(int idx){
    
    string myName = name[idx];
    
    double baseScore = double(score[myName]);
    
    double linkScore = 0;
    vector<string> inLinks = indegree[myName];
    for(int i=0;i<inLinks.size();i++){
        string link = inLinks[i];
        linkScore += (double(score[link]) / double(outdegree[link].size()));
    }
    return baseScore + linkScore;
}

int solution(string word, vector<string> pages) {
    
    int answer = 0;
    
    toSmall(word);
    for(int i=0;i<pages.size();i++)
        toSmall(pages[i]);
    
    for(int i=0;i<pages.size();i++)
        processing(word, pages[i], i);
    
    double maxScore = 0;
    for(int i=0;i<pages.size();i++){
        double nowScore = getMatchScore(i);
        if(maxScore < nowScore){
            maxScore = nowScore;
            answer = i;
        }
    }
    
    return answer;
}

문제 링크


www.acmicpc.net/problem/19238

 

19238번: 스타트 택시

첫 줄에 N, M, 그리고 초기 연료의 양이 주어진다. (2 ≤ N ≤ 20, 1 ≤ M ≤ N2, 1 ≤ 초기 연료 ≤ 500,000) 연료는 무한히 많이 담을 수 있기 때문에, 초기 연료의 양을 넘어서 충전될 수도 있다. 다

www.acmicpc.net

 

접근 방법


문제를 해결하는 과정은 아래와 같습니다.

 

1. 현재 택시로 부터 가장 가까운 손님을 탐색하기 위해선 BFS를 사용해야 합니다. 이 때 거리가 같은 손님이 여러명 존재할 수 있기 때문에 가장 가까운 손님을 탐색완료하더라도 현재 레벨 까지는 계속해서 탐색을 해야합니다. 또한 탐색을 시작하기전 현재위치에 손님이 있는지도 먼저 검사를 해야합니다.

 

2. 손님의 위치가 탐색이 완료된다면 현재의 연료를 가지고 탐색한 위치로 이동 할 수 있는지 검사 후 이동을 합니다.

 

3. 1번 항목과 마찬가지로 BFS로 탐색을 하여 손님의 도착지 까지의 거리를 알아냅니다. 

 

4. 이후 현재의 연료를 가지고 이동 할 수 있는지 검사 후 이동을 시킵니다.  

 

5. 손님이 있던 좌표의 정보를 제거합니다.

 

6. 1번 항목부터 반복

 

자세한 사항은 소스코드에 주석을 달았습니다.

소스 코드


#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string.h>
#define MAX 10000

using namespace std;

typedef struct coord {
	int x, y;
};

typedef struct tInfo {
	coord xy;
	int cost;
};

coord direction[4] = { {1,0}, {-1,0}, {0,1}, {0,-1} };
coord passengers[21][21];
int tMap[21][21];
int N, M;

bool inRange(int x, int y) {
	return (0 <= x && x < N && 0 <= y && y < N);
}

coord comp(coord one, coord other) {
	if (one.x < other.x)
		return one;
	else if (one.x == other.x) {
		if (one.y < other.y)
			return one;
		else
			return other;
	}
	else
		return other;
}

tInfo BFS(int x, int y, int state) { 
//state == 1 -> 택시가 손님에게
//state == 2 -> 손님을 태우고 목적지로

	queue <tInfo> q;
	vector<vector<bool>> visited(N, vector<bool>(N));
	coord ret = {MAX, MAX};
	int dist = 0;

	q.push({ x,y,0 });
	visited[x][y] = true;

	if (state == 1 && passengers[x][y].x != -1 && passengers[x][y].x != -1) //현재 위치에 손님이 있다면
		return { {x,y},0 };

	while (!q.empty()) {

		bool flag = false;
		int size = q.size();

		while (--size >= 0) { // 레벨 탐색

			int now_x = q.front().xy.x;
			int now_y = q.front().xy.y;
			int cost = q.front().cost;
			q.pop();

			for (int i = 0; i < 4; i++) {

				int next_x = now_x + direction[i].x;
				int next_y = now_y + direction[i].y;

				if (inRange(next_x, next_y)) {
					if (!visited[next_x][next_y] && tMap[next_x][next_y] == 0) {

						if (state == 1) { // 손님이 있는 곳으로
							if (passengers[next_x][next_y].x != -1 && passengers[next_x][next_y].x != -1) { //손님이 있는 곳
								flag = true; //탐색을 1번이라도 성공했다는 flag
								ret = comp(ret, { next_x, next_y }); //문제의 조건에 따라 손님의 우선순위 결정
								dist = cost + 1;
							}
						}
						else { //택시가 손님을 태우고 목적지로
							if (passengers[x][y].x == next_x && passengers[x][y].y == next_y) { //목적지에 도착했을 때
								ret = { next_x, next_y };
								return { ret, cost + 1};
							}
						}
						q.push({ next_x, next_y, cost + 1 });
						visited[next_x][next_y] = true;
					}
				}
			}
		}
		if (flag)
			break;
	}

	return { ret, dist };
}

bool canGo(tInfo &taxi, tInfo to, int state) {  
//state == 1 -> 택시가 손님한테 가는 동작
//state == 2 -> 손님이 목적지에 가는 동작 
	if (to.xy.x == MAX && to.xy.x == MAX)
		return false;
	if (taxi.cost - to.cost >= 0) {
		taxi.xy.x = to.xy.x;
		taxi.xy.y = to.xy.y;

		if (state == 1) // 손님을 태우러 감
			taxi.cost -= to.cost;
		else // 손님을 목적지로 이동 시킨 경우
			taxi.cost += to.cost;
			
		return true;
	}
	return false;
}

int solve(tInfo taxi) {

	while (--M >= 0) {

		tInfo toPassenger = BFS(taxi.xy.x, taxi.xy.y, 1); //1번 손님의 위치 탐색
		if (!canGo(taxi, toPassenger, 1)) //2번 손님으로 이동 가능하다면 택시 정보 갱신
			return -1;

		tInfo toDestination = BFS(taxi.xy.x, taxi.xy.y, 2); //3번 목적지의 거리와 좌표 탐색
		if (!canGo(taxi, toDestination, 2))  // 목적지로 이동 가능하다면 택시 정보 갱신
			return -1;

		passengers[toPassenger.xy.x][toPassenger.xy.y] = { -1,-1 }; //하차 후 손님 좌표의 정보 삭제
	}

	return taxi.cost;
}

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int x, y, cost;
	
	tInfo taxi;
	
	cin >> N >> M >> cost;

	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++) {
			cin >> tMap[i][j];
			passengers[i][j] = { -1,-1 }; //도착지의 정보가 0,0이 될 수 있기 때문에 -1로 초기화
		}
	
	cin >> x >> y;
	taxi = { {x - 1, y - 1}, cost };
	
	for (int i = 0; i < M; i++) {
		int x, y, next_x, next_y;
		cin >> x >> y >> next_x >> next_y;
		passengers[x - 1][y - 1] = { next_x - 1 , next_y - 1}; //출발지와 도착지 매핑
	}

	cout << solve(taxi);
}

 

문제 링크


www.acmicpc.net/problem/17406

 

17406번: 배열 돌리기 4

크기가 N×M 크기인 배열 A가 있을때, 배열 A의 값은 각 행에 있는 모든 수의 합 중 최솟값을 의미한다. 배열 A가 아래와 같은 경우 1행의 합은 6, 2행의 합은 4, 3행의 합은 15이다. 따라서, 배열 A의

www.acmicpc.net

 

접근 방법


 처음에 문제를 해결하고 나서 왜맞틀을 시전했던 문제입니다. 문제를 잘 못 이해해서 생긴 문제인데 문제에서 배열의 회전 명령어를 순차적으로 실행하는 것이 아닌 주어진 명령어의 모든 조합을 다 실행하여 그 중 최소를 구하는 문제였습니다. 

 

문제 풀이의 순서는 다음과 같습니다.

1. 가능한 명령의 조합을 구한다.

2. 한 조합에서 한 명령어를 실행한다.

3. 한 명령어를 실행한다.

4. 한 명령어에 s~1까지 순차적으로 배열을 회전 시킨다.

5. 한 조합의 명령어를 모두 실행시킨 후 배열의 값을 구한다.

6. 다음 조합도 위의 과정을 실행하며 최솟값을 갱신한다.

 

소스 코드


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

using namespace std;

typedef struct info {
	int r; int c; int s;
};

vector <vector<int>> map;
vector <info> inst;
int N, M, K;

void init() {
	
	cin >> N >> M >> K;

	for (int i = 0; i < N; i++) {
		vector<int> v;
		for (int j = 0; j < M; j++) {
			int num; cin >> num;
			v.push_back(num);
		}
		map.push_back(v);
	}
	for (int i = 0; i < K; i++) {
		int r, c, s;
		cin >> r >> c >> s;
		inst.push_back({ r - 1, c - 1, s });
	}
}

vector<vector<int>> sequence(vector<int> &seq, vector<vector<int>> &seqs, vector<bool> &visited) {

	if (seq.size() == inst.size()) {
		seqs.push_back(seq);
		return seqs;
	}
	for (int i = 0; i < inst.size(); i++) {
		if (!visited[i]) {
			visited[i] = true;
			seq.push_back(i);
			sequence(seq, seqs, visited);
			visited[i] = false;
			seq.pop_back();
		}
	}
	return seqs;
}

int findMin(vector<vector<int>> newmap) {
	
	int minimum = 0xFFFFFFF;

	for (int i = 0; i < N; i++) {
		int sum = 0;
		for (int j = 0; j < M; j++)
			sum += newmap[i][j];
		minimum = min(sum, minimum);
	}
	return minimum;
}

void rotate(int x, int y, int dist, vector<vector<int>> &ret) {

	vector<vector<int>> tmp = ret;

	for (int i = y - dist; i < y + dist; i++) 
		ret[x - dist][i + 1] = tmp[x - dist][i]; //높이 고정
	for (int i = x - dist; i < x + dist; i++)
		ret[i + 1][y + dist] = tmp[i][y + dist];  // 축 고정
	for (int i = y + dist; i > y - dist; i--)
		ret[x + dist][i - 1] = tmp[x + dist][i]; //높이 고정
	for (int i = x + dist; i > x - dist; i--)
		ret[i - 1][y - dist] = tmp[i][y - dist];  // 축 고정
}

int processing(vector<int> seq) { // 한 명령어 집합에 대한 것
	
	vector<vector<int>> newmap = map;

	for (int i = 0; i < seq.size(); i++) {

		int r = inst[seq[i]].r;
		int c = inst[seq[i]].c;
		int s = inst[seq[i]].s;

		for (int j = 1; j <= s; j++)
			rotate(r, c, j, newmap);
	}
	return findMin(newmap);
}

int solve() {
	
	vector <vector<int>> seqs;
	vector <int> seq;
	vector <bool> visited(6, false);
	int minimum = 0xFFFFFFF;

	seqs = sequence(seq, seqs, visited);

	for (int i = 0; i < seqs.size();i++) 
		minimum = min(minimum, processing(seqs[i]));
	
	return minimum;
}

int main() {
	
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	init();

	cout << solve() << "\n";
}

개발 환경 : VS2017

질문, 지적 환영합니다!

 

'알고리즘 > 백준' 카테고리의 다른 글

[C++] 백준 17472 다리만들기2  (0) 2021.01.04
[C++] 백준 17281 야구  (0) 2021.01.04
[C++] 백준 3190 뱀  (0) 2021.01.03
[C++] 백준 17136 색종이 붙이기  (0) 2021.01.02
[C++] 백준 9470 Strahler 순서  (0) 2020.09.25

문제 링크


www.acmicpc.net/problem/3190

 

3190번: 뱀

 'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다. 게임

www.acmicpc.net

 

접근 방법


 deque의 자료구조를 사용하여 어렵지 않게 구현 할 수 있는 문제였습니다. 매 시간마다 현재의 방향을 설정해줍니다. 현재 시간에 방향을 바꿔야하는 명령어가 있다면 방향을 전환합니다. 그 다음 설정된 방향으로 이동을 했을 때 4가지를 검사합니다. 

 

1. 다음 위치가 사과인지

2. 다음 위치가 뱀의 몸인지

3. 다음 위치가 벽인지(범위를 벗어났는지)

4. 다음 위치가 빈 공간인지 

 

문제에서 제시된 대로 이동에 대한 규칙은 머리를 먼저 추가합니다. 

1의 경우라면 더 이상의 처리는 없습니다.

2의 경우라면 게임을 종료합니다.

3의 경우라면 게임을 종료합니다.

4의 경우라면 가장 말단의 꼬리를 제거합니다.

 

 

소스 코드


#include <iostream>
#include <vector>
#include <deque>
#include <queue>
#define body 1
#define apple 2
#define wall 3

using namespace std;

typedef struct coord {
	int x;
	int y;
};

deque <coord> snake;
queue <pair<int, char>> inst;
coord direction[4] = { {0,1}, {1,0}, {0,-1}, {-1,0} };
int N, K, L;
int map[103][103];

bool inRange(int x, int y) {
	return (0 < x && x <= N && 0 < y && y <= N) ? true : false;
}

int nextSquare(coord head, int dir) {
	
	coord nextcoord = { head.x + direction[dir].x, head.y + direction[dir].y };

	if (map[nextcoord.x][nextcoord.y] == apple)
		return apple;
	else if (map[nextcoord.x][nextcoord.y] == body)
		return body;
	else if (!inRange(nextcoord.x, nextcoord.y))
		return wall;
	else
		return 0;
}

int change_dir(int dir, char inst) {

	dir += 4;
	if (inst == 'L')
		return (dir - 1) % 4;
	else
		return (dir + 1) % 4;
}

int now_dir(int cnt, int dir) {

	int newdir = dir;

	if (!inst.empty() && inst.front().first == cnt) {
		newdir = change_dir(dir, inst.front().second);
		inst.pop();
	}
	return newdir;
}

bool go(int dir) {
	
	coord head = snake.back();
	
	int nextState = nextSquare(head, dir);
	coord nextcoord = { head.x + direction[dir].x, head.y + direction[dir].y };
	
	snake.push_back(nextcoord);
	map[snake.back().x][snake.back().y] = body;

	if (nextState == apple) {
		return true;
	}
	else if (nextState == body) {
		return false;
	}
	else if (nextState == wall) {
		return false;
	}
	else {
		map[snake.front().x][snake.front().y] = 0;
		snake.pop_front();
		return true;
	}

}

int solve() {

	int cnt = 0;
	int dir = 0;
	
	snake.push_back({ 1,1 });
	map[1][1] = body;
	
	while (true) {
		//printmap();
		dir = now_dir(cnt, dir);
		cnt++;
		if (!go(dir))
			break;
	}
	return cnt;
}

int main() {
	
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	cin >> N;

	cin >> K;
	for (int i = 0; i < K; i++) {
		int x, y;
		cin >> x >> y;
		map[x][y] = apple;
	}

	cin >> L;
	for (int i = 0; i < L; i++) {
		int t; char dir;
		cin >> t >> dir;
		inst.push({ t, dir });
	}

	cout << solve() << endl;

}

개발 환경 : VS2017

질문, 지적 환영합니다!

'알고리즘 > 백준' 카테고리의 다른 글

[C++] 백준 17281 야구  (0) 2021.01.04
[C++] 백준 17406 배열돌리기4  (0) 2021.01.03
[C++] 백준 17136 색종이 붙이기  (0) 2021.01.02
[C++] 백준 9470 Strahler 순서  (0) 2020.09.25
[C++] 백준 17070 파이프 옮기기 1  (0) 2020.09.18

문제 링크


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

 

5373번: 큐빙

문제 루빅스 큐브는 삼차원 퍼즐이다. 보통 루빅스 큐브는 3×3×3개의 작은 정육면체로 이루어져 있다. 퍼즐을 풀려면 각 면에 있는 아홉 개의 작은 정육면체의 색이 동일해야 한다. 큐브는 각 면

www.acmicpc.net

 

문제 접근


모든 면에 대한 색상을 큐브를 돌릴 때 마다 일일히 바꿔주는 것은 고려해야할 것이 너무 많다고 생각했습니다. 제가 접근한 방법은 3x3x3의 큐브의 각 단위에 해당하는 '작은 큐브'를 정의하는 것이었습니다. '작은 큐브'는 쉽게 말해서 정육면체이며, 6가지 면에 대한 색상 정보를 담습니다. 

typedef struct cuve {
	char top, front, bot, back, left, right;
};

위의 작은 큐브를 통해서 3x3x3의 큐브를 만들어 줍니다.

cuve cuv[3][3][3];

그리고 모든 작은 큐브에 대하여 동일하게 초기화 해줍니다.

void init_cuve() {
	for (int h = 0; h < 3; ++h) {
		for (int y = 0; y < 3; ++y) {
			for (int x = 0; x < 3; ++x) {
				cuv[h][y][x].top = 'w';
				cuv[h][y][x].bot = 'y';
				cuv[h][y][x].front = 'r';
				cuv[h][y][x].back = 'o';
				cuv[h][y][x].left = 'g';
				cuv[h][y][x].right = 'b';
			}
		}
	}
}

각 작은 큐브는 표면에 노출된 면만 고정적으로 노출되므로 보이지 않는 면을 초기화 한다해도 문제 없습니다.

 

이제 큐브 정의가 끝났습니다. 이제 면(side)과 방향(direction)을 입력받아서 큐브를 회전하는 함수를 짜봅시다.

회전의 정의는 큐브의 회전은 '각 면을 정면에서 바라보았을 때의 시계/반시계 방향'으로 이루어진다고 나와있습니다.

그 말을 각 면에 대해서 그림을 그려본다면, 앞(F)면을 시계방향으로 회전하는 것과, 뒷(B)면을 반시계방향으로 회전하는 것방향이 같음을 알 수 있습니다. 또한 (h, y, x)의 좌표계에서 바라보면 앞면과 뒷면은 h좌표가 고정이고, (x, y)좌표만 움직임을 알 수 있습니다. 이를 정리하면 아래와 같습니다.

cuve[3][3][3]

- 윗면(U)/아랫면(D) : h고정(0 또는 2) xy가변, (방향관점) 윗면 시계방향 = 아랫면 반시계방향

- 앞면(F)/뒷면(B) : y고정(0 또는 2), hx가변, (방향관점) 앞면 시계방향 = 뒷면 반시계방향

- 왼쪽(L)/오른쪽(R) : x고정(0 또는 2), hy가변, (방향관점) 왼쪽 시계방향 = 오른쪽 반시계방향

 

이제 어떤 면을 선택하였을때 어떻게 좌표 접근을 해야할지 해결하였습니다.

이제 시계/반시계 방향으로 회전하는 것을 알아봅시다.

(h, y, x)로 좌표를 표현하면 위 사진과 같습니다. 윗면을 시계방향(h고정, xy가변)으로 회전하면

- (0, 0, 0) -> (0, 0, 2)로 이동합니다.

- (0, 1, 0) -> (0, 0, 1)로 이동합니다. y가 1증가 -> x가 1감소

- (0, 1, 1) -> (0, 1, 1)로 이동합니다. x가 1증가 -> y가 1증가

규칙이 보이시나요? 코드로 표현하면 아래와 같습니다. (색상은 밑에서 회전하겠습니다)

new_cuve[h][x][2 - y] = cuv[h][y][x];

위의 방법으로 다른 모든 면과 방향에 대해서 정의해줍니다.

 

윗면 시계 || 아랫면 반시계 = new_cuve[h][x][2 - y] = cuv[h][y][x];

윗면 반시계 || 아랫면 시계 = new_cuve[h][2 - x][y] = cuv[h][y][x];

앞면 시계 || 뒷면 반시계 = new_cuve[x][y][2 - h] = cuv[h][y][x];

앞면 반시계 || 뒷면 시계 = new_cuve[2 - x][y][h] = cuv[h][y][x];

오른쪽 시계 || 왼쪽 반시계 = new_cuve[2 - y][h][x] = cuv[h][y][x];

오른쪽 반시계 || 왼쪽 시계 = new_cuve[y][2 - h][x] = cuv[h][y][x];

 

자 이제 방향과 좌표 정리가 끝났습니다. 이제 남은건 회전하면서 작은 큐브의 색상도 회전해주는 일입니다.

이 부분은 각 면마다 작은 큐브가 회전하는 방향이 달라서 규칙을 찾는데 실패했습니다. 하지만 매우 간단한 코드이기 때문에 괜찮습니다..

 

윗면 시계 || 아랫면 반시계 = back -> right -> front -> left -> back같은 순으로 4가지 색상을 옮겨주기만 하면 됩니다!

이 부분에 더 좋은 접근 방법이 있다면 다른 글을 참고해주세요. 저는 생각이 나지 않았습니다..

 

윗면 반시계 || 아랫면 시계 = back -> left -> front -> right -> back

앞면 시계 || 뒷면 반시계 = top -> right -> bot -> left -> top

앞면 반시계 || 뒷면 시계 = top -> left -> bot -> right -> top

오른쪽 시계 || 왼쪽 반시계 = top -> back -> bot -> front -> top

오른쪽 반시계 || 왼쪽 시계 = top -> front -> bot -> back -> top

 

회전 소스 코드는 아래와 같습니다.

// 큐브 from에서 큐브 to로 값을 복사
void copy_cuve(cuve from[][3][3], cuve to[][3][3]) {
	int h, y, x;
	for (h = 0; h < 3; ++h)
		for (y = 0; y < 3; ++y)
			for (x = 0; x < 3; ++x)
				to[h][y][x] = from[h][y][x];
}

// 명령어를 입력받고 면을 회전하는 코드 (side: 면, direction: 시계/반시계)
void rotate(char side, char direction) {
	char temp;
	int h, y, x;
	cuve new_cuve[3][3][3];
	copy_cuve(cuv, new_cuve);
	if (side == 'U' || side == 'D') { // 윗면 또는 아랫면인 경우 (h고정, yx가변)
		h = (side == 'U' ? 0 : 2); // 높이 고정
		if ((direction == '+' && side == 'U') ||
			(direction == '-' && side == 'D')) {
			// 윗면 시계, 바닥면 반시계
			for (y = 0; y < 3; ++y) {
				for (x = 0; x < 3; ++x) {
					// back -> right -> front -> left -> back
					temp = cuv[h][y][x].left;
					cuv[h][y][x].left = cuv[h][y][x].front;
					cuv[h][y][x].front = cuv[h][y][x].right;
					cuv[h][y][x].right = cuv[h][y][x].back;
					cuv[h][y][x].back = temp;

					new_cuve[h][x][2 - y] = cuv[h][y][x];
				}
			}
		}
		else { // 윗면 반시계, 바닥면 시계
			for (y = 0; y < 3; ++y) {
				for (x = 0; x < 3; ++x) {
					// back -> left -> front -> right -> back
					temp = cuv[h][y][x].right;
					cuv[h][y][x].right = cuv[h][y][x].front;
					cuv[h][y][x].front = cuv[h][y][x].left;
					cuv[h][y][x].left = cuv[h][y][x].back;
					cuv[h][y][x].back = temp;

					new_cuve[h][2 - x][y] = cuv[h][y][x];
				}
			}
		}
	}
	else if (side == 'F' || side == 'B') { // 앞면 또는 뒷면인 경우 (y고정, hx가변)
		y = (side == 'F' ? 2 : 0); // y 고정 (앞면: 2, 뒷면: 0)
		if ((direction == '+' && side == 'F') ||
			(direction == '-' && side == 'B')) { // 앞면 시계, 뒷면 반시계
			for (h = 0; h < 3; ++h) {
				for (x = 0; x < 3; ++x) {
					// top -> right -> bot -> left -> top
					temp = cuv[h][y][x].left;
					cuv[h][y][x].left = cuv[h][y][x].bot;
					cuv[h][y][x].bot = cuv[h][y][x].right;
					cuv[h][y][x].right = cuv[h][y][x].top;
					cuv[h][y][x].top = temp;

					new_cuve[x][y][2 - h] = cuv[h][y][x];
				}
			}
		}
		else { // 앞면 반시계, 뒷면 시계
			for (h = 0; h < 3; ++h) {
				for (x = 0; x < 3; ++x) {
					// top -> left -> bot -> right -> top
					temp = cuv[h][y][x].right;
					cuv[h][y][x].right = cuv[h][y][x].bot;
					cuv[h][y][x].bot = cuv[h][y][x].left;
					cuv[h][y][x].left = cuv[h][y][x].top;
					cuv[h][y][x].top = temp;

					new_cuve[2 - x][y][h] = cuv[h][y][x];
				}
			}
		}
	}
	else if (side == 'L' || side == 'R') { // 왼쪽 또는 오른쪽 (x고정, hy가변) 
		x = (side == 'L' ? 0 : 2); // x 고정 (왼쪽: 0, 오른쪽: 2)
		if ((direction == '+' && side == 'R') ||
			(direction == '-' && side == 'L')) { 
			// 오른쪽 시계, 왼쪽 반시계
			for (h = 0; h < 3; ++h) {
				for (y = 0; y < 3; ++y) {
					// top -> back -> bot -> front -> top
					temp = cuv[h][y][x].front;
					cuv[h][y][x].front = cuv[h][y][x].bot;
					cuv[h][y][x].bot = cuv[h][y][x].back;
					cuv[h][y][x].back = cuv[h][y][x].top;
					cuv[h][y][x].top = temp;

					new_cuve[2 - y][h][x] = cuv[h][y][x];
				}
			}
		}
		else { // 오른쪽 반시계, 왼쪽 시계
			for (h = 0; h < 3; ++h) {
				for (y = 0; y < 3; ++y) {
					// top -> front -> bot -> back -> top
					temp = cuv[h][y][x].back;
					cuv[h][y][x].back = cuv[h][y][x].bot;
					cuv[h][y][x].bot = cuv[h][y][x].front;
					cuv[h][y][x].front = cuv[h][y][x].top;
					cuv[h][y][x].top = temp;

					new_cuve[y][2 - h][x] = cuv[h][y][x];
				}
			}
		}
	}
	copy_cuve(new_cuve, cuv); // new -> cuv로 copy
}

 

소스 코드


#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct cuve {
	char top, front, bot, back, left, right;
};
cuve cuv[3][3][3];	

void init_cuve() {
	for (int h = 0; h < 3; ++h) {
		for (int y = 0; y < 3; ++y) {
			for (int x = 0; x < 3; ++x) {
				cuv[h][y][x].top = 'w';
				cuv[h][y][x].bot = 'y';
				cuv[h][y][x].front = 'r';
				cuv[h][y][x].back = 'o';
				cuv[h][y][x].left = 'g';
				cuv[h][y][x].right = 'b';
			}
		}
	}
}

// 큐브 from에서 큐브 to로 값을 복사
void copy_cuve(cuve from[][3][3], cuve to[][3][3]) {
	int h, y, x;
	for (h = 0; h < 3; ++h)
		for (y = 0; y < 3; ++y)
			for (x = 0; x < 3; ++x)
				to[h][y][x] = from[h][y][x];
}

// 명령어를 입력받고 면을 회전하는 코드 (side: 면, direction: 시계/반시계)
void rotate(char side, char direction) {
	char temp;
	int h, y, x;
	cuve new_cuve[3][3][3];
	copy_cuve(cuv, new_cuve);
	if (side == 'U' || side == 'D') { // 윗면 또는 아랫면인 경우 (h고정, yx가변)
		h = (side == 'U' ? 0 : 2); // 높이 고정
		if ((direction == '+' && side == 'U') ||
			(direction == '-' && side == 'D')) {
			// 윗면 시계, 바닥면 반시계
			for (y = 0; y < 3; ++y) {
				for (x = 0; x < 3; ++x) {
					// back -> right -> front -> left -> back
					temp = cuv[h][y][x].left;
					cuv[h][y][x].left = cuv[h][y][x].front;
					cuv[h][y][x].front = cuv[h][y][x].right;
					cuv[h][y][x].right = cuv[h][y][x].back;
					cuv[h][y][x].back = temp;

					new_cuve[h][x][2 - y] = cuv[h][y][x];
				}
			}
		}
		else { // 윗면 반시계, 바닥면 시계
			for (y = 0; y < 3; ++y) {
				for (x = 0; x < 3; ++x) {
					// back -> left -> front -> right -> back
					temp = cuv[h][y][x].right;
					cuv[h][y][x].right = cuv[h][y][x].front;
					cuv[h][y][x].front = cuv[h][y][x].left;
					cuv[h][y][x].left = cuv[h][y][x].back;
					cuv[h][y][x].back = temp;

					new_cuve[h][2 - x][y] = cuv[h][y][x];
				}
			}
		}
	}
	else if (side == 'F' || side == 'B') { // 앞면 또는 뒷면인 경우 (y고정, hx가변)
		y = (side == 'F' ? 2 : 0); // y 고정 (앞면: 2, 뒷면: 0)
		if ((direction == '+' && side == 'F') ||
			(direction == '-' && side == 'B')) { // 앞면 시계, 뒷면 반시계
			for (h = 0; h < 3; ++h) {
				for (x = 0; x < 3; ++x) {
					// top -> right -> bot -> left -> top
					temp = cuv[h][y][x].left;
					cuv[h][y][x].left = cuv[h][y][x].bot;
					cuv[h][y][x].bot = cuv[h][y][x].right;
					cuv[h][y][x].right = cuv[h][y][x].top;
					cuv[h][y][x].top = temp;

					new_cuve[x][y][2 - h] = cuv[h][y][x];
				}
			}
		}
		else { // 앞면 반시계, 뒷면 시계
			for (h = 0; h < 3; ++h) {
				for (x = 0; x < 3; ++x) {
					// top -> left -> bot -> right -> top
					temp = cuv[h][y][x].right;
					cuv[h][y][x].right = cuv[h][y][x].bot;
					cuv[h][y][x].bot = cuv[h][y][x].left;
					cuv[h][y][x].left = cuv[h][y][x].top;
					cuv[h][y][x].top = temp;

					new_cuve[2 - x][y][h] = cuv[h][y][x];
				}
			}
		}
	}
	else if (side == 'L' || side == 'R') { // 왼쪽 또는 오른쪽 (x고정, hy가변) 
		x = (side == 'L' ? 0 : 2); // x 고정 (왼쪽: 0, 오른쪽: 2)
		if ((direction == '+' && side == 'R') ||
			(direction == '-' && side == 'L')) { 
			// 오른쪽 시계, 왼쪽 반시계
			for (h = 0; h < 3; ++h) {
				for (y = 0; y < 3; ++y) {
					// top -> back -> bot -> front -> top
					temp = cuv[h][y][x].front;
					cuv[h][y][x].front = cuv[h][y][x].bot;
					cuv[h][y][x].bot = cuv[h][y][x].back;
					cuv[h][y][x].back = cuv[h][y][x].top;
					cuv[h][y][x].top = temp;

					new_cuve[2 - y][h][x] = cuv[h][y][x];
				}
			}
		}
		else { // 오른쪽 반시계, 왼쪽 시계
			for (h = 0; h < 3; ++h) {
				for (y = 0; y < 3; ++y) {
					// top -> front -> bot -> back -> top
					temp = cuv[h][y][x].back;
					cuv[h][y][x].back = cuv[h][y][x].bot;
					cuv[h][y][x].bot = cuv[h][y][x].front;
					cuv[h][y][x].front = cuv[h][y][x].top;
					cuv[h][y][x].top = temp;

					new_cuve[y][2 - h][x] = cuv[h][y][x];
				}
			}
		}
	}
	copy_cuve(new_cuve, cuv); // new -> cuv로 copy
}

void print_cuve() {
	for (int y = 0; y < 3; ++y) {
		for (int x = 0; x < 3; ++x) {
			cout << cuv[0][y][x].top;
		}
		cout << "\n";
	}
}

int main() {
	ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
	int T, N;
	char side, direction;
	cin >> T;
	for (int t = 0; t < T; ++t) {
		init_cuve();
		cin >> N;
		for (int i = 0; i < N; ++i) {
			cin >> side >> direction;
			rotate(side, direction);
		}
		print_cuve();
	}
	return 0;
}

개발 환경 : VS2019

질문, 지적 환영합니다!

'알고리즘 > 백준' 카테고리의 다른 글

[C++] 백준 17837 새로운 게임 2  (0) 2020.05.29
[C++] 백준 1520 내리막길  (0) 2020.05.26
[C++] 백준 13460 구슬 탈출 2  (0) 2020.05.26
[C++] 백준 15684 사다리 조작  (0) 2020.05.25
[C++] 백준 14891 톱니바퀴  (0) 2020.05.25

+ Recent posts