[풀이]

먼저 각 그래프의 특징을 파악하면 된다.

막대 그래프

막대 그래프의 경우 다른 그래프에서는 존재하지 않는 

나가는 간선이 없고 들어오는 간선은 1개 이상인 정점이 한개 존재한다.

 

size가 1인 경우에도 새로 추가한 정점으로부터 나온 간선이 들어오기 때문에 

들어오는 간선은 무조건 1개 이상 존재하게 된다.

 

 

8자 그래프

8자 그래프의 경우는 나가는 간선 2개 그리고 들어오는 간선이 2개

따라서 총 4개의 간선이 존재하는 정점 한개가 존재한다.

 

8자 그래프

사실 8자 그래프의 경우, 8자 그래프에만 존재하는 특징을 따로 찾을 수 없었다.

 

하지만 다행히 문제에서 기존의 그래프가 존재하는 상황에서 이 그래프와 무관한 정점을 하나 추가하고, 

정점에서 각 그래프로 향하는 간선들을 연결했다.

이 말에 의하면 새로 추가한 정점의 나가는 간선 수가 총 그래프의 개수가 된다.

따라서 8자 그래프의 개수 = 새로 추가한 정점의 나가는 간선 개수 - (도넛 그래프 수 + 막대 그래프 수) 가 된다.

 

또한 문제 제한 사항에서 아래와 같이 주어졌기 때문에

도넛 모양 그래프, 막대 모양 그래프, 8자 모양 그래프의 수의 합은 2이상입니다.

정점 중에서 나가는 간선만 2개 이상 존재하고, 들어오는 간선이 없는 정점을 발견한다면 해당 정점이 새로 추가한 정점이 된다.

그리고 해당 정점의 나가는 간선 개수가 전체 그래프 개수가 되는 것이다.

 

위의 정보들을 기반으로 코드를 구현했다.

나가는 간선, 들어오는 간선 정보를 저장하기 위해 output, input 배열을 선언했다.

edges 정보를 기반으로 각 정점별 output, input 간선들을 count 했다.

 

그리고 각 정점들의 input, output 간선들의 개수를 기반으로 

8자 그래프 , 막대 그래프, 새로 추가된 정점의 번호를 알 수 있었다.

 

이를 기반으로

새로 추가한 정점의 나가는 간선 개수 - (도넛 그래프 수 + 막대 그래프 수)  값을 계산하여 도넛 그래프의 개수도 알 수 있었다.

 

[코드]

class Solution {
    static final int MAX = 1_000_000;

    public int[] solution(int[][] edges) {
        int MAX_IDX =0;
        int[] input, output;

        input = new int[MAX+1];
        output = new int[MAX+1];

        for(int[] edge : edges) {
            output[edge[0]]++;
            input[edge[1]]++;
            MAX_IDX = Math.max(MAX_IDX, Math.max(edge[0],edge[1]));
        }

        int totalGraph = 0;
        // 각 그래프 개수
        int stickGraph = 0;
        int donutGraph = 0;
        int eightGraph = 0;
        // 새로 추가된 노드 번호
        int edgeIdx = 0;
        for(int idx = 1; idx<= MAX_IDX; idx++) {
            if(input[idx] >= 2 && output[idx] >= 2) eightGraph++;
            else if(output[idx] == 0 && input[idx] > 0)   stickGraph++;
            else if(output[idx] >= 2 && input[idx] == 0) {
                edgeIdx = idx;
                totalGraph=output[idx];
            }
        }
        donutGraph =totalGraph-(eightGraph+stickGraph);
        int[] answer = {edgeIdx, donutGraph, stickGraph, eightGraph};
        return answer;
    }
}

[문제]

https://school.programmers.co.kr/learn/courses/30/lessons/258711

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

[풀이]

2024년 카카오 겨울인턴십 코테 문제이다.

문제의 조건을 잘 읽고 , 조건에 맞게 구현하면 되는 단순 구현 문제이다.

 

모두 map을 사용해서 각각의 데이터들을 관리했다.

먼저 선물을 주고받은 내용을 기록하기 위해 2차원 map인 gift_record라는 변수를 선언했다.

key 값에 선물을 준 사람의 이름을 넣고, 2번째 map에는 누구에서 몇개의 선물을 줬는지에 대한 데이터를 저장한다.

첫번째 예시를 기준으로 보면 아래와 같이 gift_record가 존재하게 된다.

{'muzi', {'frodo',2}}

{'ryan', {'muzi',3}}

{'frodo', {{'muzi',1}, {'ryan',1}}}

{'neo', {'muzi',1}}

그리고 각 사람들의 선물 지수를 기록하기 위해 gift_score 라는 1차원 map을 선언했다.

key 값을 사람의 이름이 되고 , value는 선물 지수 값이 된다.

 

선물 지수는 (준 선물의 개수 - 받은 선물의 개수) 이므로 

사실상 선물을 줄 때는 현재 선물 지수에 +1을 해주고

선물을 줄 때는 현재 선물 지수에 -1을 해주면 된다. 

따라서 gift_record, gift_score 의 값을 동시에 채워줬다.

 

Java에서 Map 인터페이스의 getOrDefault 메서드를 사용해 map의 value 값을 할당해줬다.

특정 키를 조회할 때, 해당 키가 존재하면 해당 키 값을 / 존재하지 않을 경우 기본값(default value)을 반환해준다.

 

마지막으로 gift_record를 기반으로 다음 달에 받을 선물을 계산했다.

1. 서로 선물을 주고 받은 경우 선물을 적게 준 사람이 더 많이 준 사람에게 담달에 선물을 하나 주고 

2. 하나도 주고 받지 않았거나 , 주고 받은 개수가 같을 경우에는 선물 지수를 기반으로 담달 선물을 준다

2-1 선물 지수가 작은 사람이 큰 사람에게 담달에 선물 1개를 주면 된다.

 

여기서는 선물을 받는 사람을 기준으로만 계산을 했다. 

따라서 위의 조건을 만족하여 선물을 받는 사람일 경우 gift_cnt에서 받는 사람에 해당하는 value에 1을 더해줬다.

 

마지막으로 Collections을 사용해 gift_cnt의 value중 최대값을 구하였다.

Collections는 java.util 패키지에 포함된 유틸리티 클래스로, 컬렉션(Collection) 객체를 쉽게 조작하고 관리할 수 있도록 sort, search, min, max와 같이 다양한 정적 메서드를 제공한다.

 

[코드]

import java.util.Map;
import java.util.HashMap;
import java.util.Collections;

class Solution {
    
    static int[][] gift_cnt = new int [50][];


    public int solution(String[] friends, String[] gifts) {
        int answer = 0;
        //선물 기록 관리
        Map<String, Map<String, Integer>> gift_record= new HashMap<>();
        // 선물 지수
        Map<String, Integer> gift_score = new HashMap<>();
        // 받을 선물 개수
        Map<String, Integer> gift_cnt = new HashMap<>();
    


        for(String friend : friends) { 
            gift_record.put(friend, new HashMap<>());
            gift_score.put(friend,0);
            gift_cnt.put(friend,0);
        }
            
        for (String gift : gifts) {
            String person[] = gift.split(" ");
            String from = person[0];
            String to = person[1];

            gift_record.get(from).put(to, gift_record.get(from).getOrDefault(to, 0) + 1);
            gift_score.put(from, gift_score.get(from) + 1);
            gift_score.put(to, gift_score.get(to) - 1);
        }

        for(String from : friends) { 
            for(String to : friends) { 
                if(!from.equals(to)) {
                    int from_cnt = gift_record.get(from).getOrDefault(to, 0); //from이 to에게 준 선물의 개수
                    int to_cnt = gift_record.get(to).getOrDefault(from, 0); //to가 from에게 준 선물의 개수
                    if(from_cnt > to_cnt) {
                        gift_cnt.put(from, gift_cnt.get(from) + 1);
                    } else if (from_cnt == to_cnt && gift_score.get(from) > gift_score.get(to)) {
                            gift_cnt.put(from, gift_cnt.get(from) + 1);
                    } 
                }
            }
        }


        return Collections.max(gift_cnt.values());
    }
}

 

[문제]

https://school.programmers.co.kr/learn/courses/30/lessons/258712

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

[풀이]

 

단순 구현 문제로 문제 조건만 잘 맞추고 문자열을 잘 다뤄주면 된다.

나는 우선 시간들을 convertTime 함수를 통해 int형으로 바꿔놓고 시작했다.

 

시간 string을 읽어와 분/초를 분리한뒤 {60*분 + 초}를 사용해 int형으로 계산했다.

이를 기반으로 commands의 작업들으 수행했는데 

 

1. check_opening을 통해 현재 시간이 opening 구간에 존재하는지 판단

2. prev, next 인지에 따라 시간 계산하도록 구현했다.

 

위의 과정을 반복하며 현재 시간을 계산한 뒤 

convertTimeToString 함수를 통해 현재 시간을 다시 mm:ss 타입의 String으로 변환하도록 하였다.

String.format 함수를 사용하여 문자열의 형식을 지정해줬다.

 

 

[코드]

 
class Solution {
    static int cur_pos;

    public String solution(String video_len, String pos, String op_start, String op_end, String[] commands) {
        int video_len_int = convertTime(video_len);
        int op_start_int = convertTime(op_start);
        int op_end_int = convertTime(op_end);
        cur_pos = convertTime(pos);
        
        for (String command : commands) {
            check_opening(op_start_int, op_end_int);
            if(command.equals("prev"))  move_prev();
            else move_next(video_len_int);
        }
        check_opening(op_start_int, op_end_int);
        return convertTimeToString();
    }
    
    public static void move_prev() {
        if(cur_pos - 10 <= 0)   cur_pos = 0;
        else    cur_pos -= 10;
    }
    
    public static void move_next(int end_time) {
        if(cur_pos + 10 >= end_time)   cur_pos = end_time;
        else    cur_pos += 10;
    }
    
    public static int convertTime(String time) {
        String[] parts = time.split(":");

        int min = Integer.parseInt(parts[0]); // 분
        int sec = Integer.parseInt(parts[1]); // 초
        return 60 * min + sec;
    }
    
    public void check_opening(int op_start, int op_end) {
        if(op_start <= cur_pos && op_end >= cur_pos){
            cur_pos = op_end;
        }
        return;
    }
    
	// mm:ss 형식의 문자열로 변환
    public static String convertTimeToString() {
        int minutes = cur_pos / 60;
        int seconds = cur_pos % 60;

        String formattedTime = String.format("%02d:%02d", minutes, seconds);
        return formattedTime;
    }
}

 

[문제]

https://school.programmers.co.kr/learn/courses/30/lessons/340213

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

재귀 문제로 유명한 하노이의 탑

나무위키에 등록될 정도이다.

 

https://school.programmers.co.kr/learn/courses/30/lessons/12946?language=java

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

알고보니 굉장히 간단한 문제였다.

시작점을 a , 경유지를 b, 목적지를 c라고 하면

원판을 목적지까지 다 옮기기 위해서는 결국 



1. a  지점에서 제일 아래에 존재하는 가장 큰 원반을 제외한 원반들은 b 옮겨져야 한다.

2. 그리고 가장 큰 원반을 c로 옮기고

 3. b에 존재하는 원반들을 a 지점을 경유지로 두고 c로 옮겨야 한다.

1,2,3의 과정을 모두 수행하는 곳이 move 함수가 되는 것이다.

이걸 move 함수로 보면 a가 start, b가 tmp, c가 end가 된다.

 

 

import java.util.*;
class Solution {
    private static List<int[]> arr = new ArrayList<>();

    public int[][] solution(int n) {
        move(1,2,3,n);
        int[][] answer = arr.stream()
                .toArray(int[][]::new);

        return answer;
    }
    
    private static void move(int start, int tmp, int end, int cnt) {
         if(cnt == 0) {
             return;
         }
        move(start, end, tmp, cnt-1);
        arr.add(new int[]{start,end});
        move(tmp, start, end, cnt-1);
    }
}

 

요즘 tailwind CSS를 사용해서 스타일을 적용하고 있는데 기존에 사용하던 CSS와는 달라

스타일을 적용하다가 막히는 부분이 생긴다.

그래서 공식 문서를 참고하여 적용하고 있다.

아래 사진과 같이 기존 css 문법에 해당하는 TailWind CSS 문법을 알려줘서 굉장히 보기가 편하다. 

 

 

[Custom Font 사용하기 ]

여러 사이트에서 무료 폰트들을 많이 제공하고 있다.

나는 보통 https://noonnu.cc/ 여기서 많이 사용한다.

다양한 예쁜 폰트들을 무료로 제공해줘서 매우 유용하게 쓰고있다.

 

원하는 폰트를 찾아 클릭해서 들어가면 사진과 같이 font-face 값이 제공된다.

해당 값을 그대로 복사하여 nextJS 프로젝트의 globals.css 파일에 넣어주면 된다.

 

그리고 추가한 폰트를 nextJs 프로젝트에 존재하는 tailwind.config.js 파일에 사진과 같이 넣어주면 된다.

 

그리고 실제 코드에서 아래와 같이 사용하면 된다.

<ul className="font-establishRetrosansOTF">

 

[Custom Color 사용하기 ]

마찬가지로 원하는 색상을 적용하고 싶으면 tailwind.config.js 파일에 아래와 같이 원하는 색상을 등록해주면 된다.

아래 코드와 같이 등록한 색상을 사용하면 된다.

<ul className="text-customBlue">

 

커밋 메시지 컨벤션은 프로젝트에서 일관된 커밋 메시지 형식을 사용하도록 정하는 규칙입니다. 이를 도입하면 여러 가지 이점이 있어 협업과 코드 관리가 훨씬 효율적입니다.

 

GitHub에서 프로젝트의 커밋 메시지 형식을 일관되게 유지하려면 다음 방법을 통해 사용할 수 있습니다.

 

1. Commit Message Convention 정하기

프로젝트 팀에서 사용할 커밋 메시지 규칙을 정해야 합니다. 예를 들어, 다음과 같은 규칙을 사용할 수 있습니다:

  • [type] subject 형식:
    • feat: 새로운 기능 추가
    • fix: 버그 수정
    • docs: 문서 관련 작업
    • style: 코드 스타일 변경 (동작에는 영향 없음)
    • refactor: 리팩토링
    • test: 테스트 추가 또는 수정
    • chore: 기타 변경 사항 (빌드 설정, 도구 추가 등)

2. 템플릿 파일 생성

 

아래 명령어를 실행해 .gitmessage.txt 파일을 생성

touch .gitmessage.txt

 

해당 파일을 아래와 같이 원하는 커밋 메세지 형식으로 설정합니다.

# 커밋 메시지 템플릿
# [type]: 설명 (동사를 사용하여 간결하게 작성)
#
# 예: feat: 로그인 페이지 디자인 개선
#
# type 종류:
# feat: 새로운 기능
# fix: 버그 수정
# docs: 문서 관련 작업
# style: 코드 스타일 변경
# refactor: 코드 리팩토링

 

#로 시작하는 부분은 주석으로 커밋에 반영되지 않는다.

 

아래 커맨드를 통해 커밋 메세지로 등록

git config --global commit.template ~/.gitmessage.txt

 

이후 git commit을 실행하면 템플릿 내용이 기본으로 표시됩니다.

[문제]

https://www.codetree.ai/problems/collect-coins/description

 

코드트리

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

[풀이]

 

삼성전자 공채 모의 코딩테스트가 코드트리에 있길래 한번 풀어봤다. 굉장히 삼성스러운 문제..

 

NXN 격자에는  동전과  벽이 존재하며 주어진 시작점과 끝점 까지의 최단 거리를 구하면 된다.

시작점에서 끝점으로 가기 위해서는 최소 3개의 동전을 획득해야 하며 획득하는 동전의 순서는 동전의 번호가 작은 것부터 오름차순으로 획득할 수 있다.

또한 동전이 있는 곳을 지나가도 동전을 가져가지 않을 수 있으며 지나간 위치를 다시 지나갈 수 있다.

BFS와  DFS를 사용해 문제를 해결했다.

 

먼저 주어진 동전의 정보를 coin 이라는 벡터에 저장해두었다. 그리고 coin 벡터를 동전 번호를 기준으로 오름차순 정렬을 해주었다.

그리고 DFS를 통해 coin 벡터에 담긴 순서대로 동전을 선택하여 selectedCoin 벡터에 coin 벡터에서의 해당  동전의 index를 push했다.

DFS를 사용해 동전의 숫자가 오름차순으로 3개의 동전을 선택하여 최단거리를 구하였다.

최단거리를 구하는 방법으로는 BFS를 사용해 시작지점부터 종점부분까지의 거리를 구했다.

BFS는 최초 방문이 최단 경로가 되므로 queue에서 pop한 좌표가 종점인 경우 break 하도록 추가해줬다. (이거 안해주면 시간초과 발생)

최단거리 =  시작점부터 첫번째 동전까지의 거리 + 첫번째 동전 to 두번째 동전 거리 + 두번째 동전 to 세번째 동전 거리 + 세번째 동전 to 종점까지의 거리 

 

이 때 각 거리 계산 중 이동할 수 없는 좌표가 발생한다면 해당경로는 불가능한 경로이므로 -1을 return 하여 이동 불가능한 경로로 처리하였다.

 

[코드]

 

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

#define MAX 20

using namespace std;

struct pos{
    int x,y;
};

struct coinInfo{
    int idx,x,y;
};

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int res=MAX*MAX;
int map[MAX][MAX]={0,};
int N;

pos startPos,endPos;

vector<coinInfo> coin;
vector<int> selected;

bool comp(coinInfo a, coinInfo b)
{
    if ( a.idx < b.idx) return true;
    return false;
}

int BFS(pos from, pos to)
{
    int visited[MAX][MAX]={0,};
    queue<pos> q;
    q.push(from);
    visited[from.x][from.y]=1;
    while(!q.empty()){
        int x= q.front().x;
        int y= q.front().y;
        q.pop();
        if(x==to.x && y == to.y)    break;
        for(int d=0;d<4;d++){
            int nx = x+dx[d];
            int ny = y+dy[d];
            
            if(nx<0||ny<0||nx>=N||ny>=N||map[nx][ny]==-1||visited[nx][ny] != 0)   continue;
            visited[nx][ny] = visited[x][y] + 1;
            q.push({nx,ny});
        }
    }
    
    return visited[to.x][to.y]-1;
}

int isPossible()
{
    int totalLen =0;
    int fromX,fromY;
    int toX, toY;
    
    for(int i=0;i<4;i++){
        if(i == 0){
            fromX = startPos.x; fromY = startPos.y;
            toX = coin[selected[i]].x;  toY = coin[selected[i]].y;
        } else if( i == 3){
            fromX = coin[selected[2]].x;    fromY = coin[selected[2]].y;
            toX = endPos.x;  toY = endPos.y;
        } else {
            fromX = coin[selected[i-1]].x;    fromY = coin[selected[i-1]].y;
            toX = coin[selected[i]].x;  toY = coin[selected[i]].y;
        }
        int len = BFS({fromX,fromY},{toX,toY});
        if( len == -1){
            totalLen = -1;
            break;
        }   else    totalLen += len;
    }
    
    return totalLen;
}

void selectCoin(int cnt, int idx)
{
    if( cnt == 3){
        int len = isPossible();
        if( len == -1)  return;
        if( len < res)  res = len;
        return ;
    }
    for(int i=idx;i<coin.size();i++){
        selected.push_back(i);
        selectCoin(cnt+1, i+1);
        selected.pop_back();
    }
}

void input()
{
    cin >> N;
    for(int i=0;i<N;i++){
        string str;
        cin >> str;
        for(int j=0;j<N;j++){
            
            if(str[j] == '#')   map[i][j]=-1;
            else if(str[j] == '.')  map[i][j]=0;
            else if(str[j] == 'S')  startPos={i,j};
            else if(str[j] == 'E')  endPos={i,j};
            else{
                map[i][j] = str[j] - '0';
                coin.push_back({map[i][j] , i, j});
            }
        }
    }
}

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    input();
    // 코인 오름차순 정렬
    sort(coin.begin(), coin.end(), comp);
    selectCoin(0,0);
    if(res == MAX*MAX)    cout << "-1";
    else    cout << res;
    
    return 0;
}

 

'알고리즘' 카테고리의 다른 글

[코드트리] 예술성 (C++)  (0) 2022.10.13
[코드트리] 나무박멸 (C++)  (0) 2022.10.12
[코드트리] 술래잡기 (C++)  (0) 2022.10.10

[문제]

https://www.codetree.ai/frequent-problems/artistry/description

 

코드트리

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

 

[풀이]

 

삼성전자 2022 상반기 오전 2번 문제.

N*N 격자에 대해 각 칸의 대한 색깔이 input으로 들어온다.

 

초기 예술 점수( 회전 안함) + 1회전 후 예술 점수 + 2회전 후 예술 점수 + 3회전 후 예술 점수를 출력해주면 된다.

 

  1. 회전
  2. 예술 점수 계산

각 step 별로 api를 구현하여 예술 점수를 계산하도록 했다.

 

초기에는 회전을 하지않고 예술 점수를 구하므로 calcScore api에서 예술 점수를 구하도록 했다.

 

calcScore에서는 BFS를 사용해 연속된 동일한 색깔끼리 그룹화를 하였다.

groupCnt를 통해 총 그룹의 개수를 저장

groupSize 배열에는 각 그룹에 대한 크기, groupIdx는 그룹에 해당하는 실제 색깔을 저장

또한 group 배열에는 grouping한 그룹의 index를 저장했다.

문제의 예시를 기준으로 보면 group 이차원 배열에는 다음과 같이 저장되어 있다.

1 2 2 3 3
2 2 2 3 3
2 2 4 3 4
2 2 4 4 4
2 2 4 4 4

그룹화를 마치면 calcTouch api에서 각 그룹별 맞닿는 변의 개수를 구하여 touch라는 이차원 배열에 저장해줬다.

각 칸 별로 아래 방향. 오른쪽 방향에 있는 칸을 확인하여 자신의 그룹과 다른 그룹이면 touch 배열의 [from][to]칸에 +1을 해주었다. 

각 칸 별로 아래, 오른쪽 방향에 대해서만  확인을 해주므로 두 개의 그룹이 맞닿는 변의 개수는 touch[from][to] + touch[to][from]이 된다.

 

이와 같이 맞닿는 변의 개수까지 구해주면 예술 점수를 구할 수 있다.

 

다음으로 rotate api를 통해 회전을 해주었다.

회전은 각 격자별 90도 시계 방향 회전이 있고 십자가 모양 부분을 90도 반시계 회전을 한다.

격자별 90도 시계 방향 회전을 인자가 다른 rotate api를 하나 더 선언하여 각 격자의 시작점을 인자 값으로 넘겨주었다.

 

 

[코드]

 

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>

#define MAX 30

using namespace std;

struct pos{
    int x,y;
};

int dx[4] ={ -1,0,1,0};
int dy[4] = {0,1,0,-1};

int N;
int map[MAX][MAX]={0,};
int group[MAX][MAX]={0,};
int touch[MAX*MAX][MAX*MAX]={0,};

void calcTouch()
{
    memset(touch, 0, sizeof(touch));

    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            int from = group[i][j];
            for(int k=1;k<=2;k++){
                int nx = i + dx[k];
                int ny = j + dy[k];
                
                if( nx <0 || ny <0 || nx >= N || ny >= N || group[nx][ny] == from)   continue;
                touch[from][group[nx][ny]]++;
            }
        }
    }
}

int calcScore()
{
    memset(group, 0, sizeof(group));

    int groupCnt=1;
    int groupSize[MAX*MAX]={0,};
    int groupIdx[MAX*MAX]={0,};
    queue<pos> q;

    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if( group[i][j] == 0){
                q.push({i,j});
                group[i][j]=groupCnt;
                groupIdx[groupCnt] = map[i][j];
                groupCnt+=1;
            }
            while(!q.empty()){
                int x= q.front().x;
                int y= q.front().y;
                q.pop();
                
                groupSize[group[x][y]]++;

                for(int k=0;k<4;k++){
                    int nx = x+dx[k];
                    int ny = y+dy[k];
                    
                    if( nx <0 || ny <0 || nx >= N || ny >= N || group[nx][ny] != 0)   continue;
                    if( map[nx][ny] != map[x][y])   continue;
                    
                    q.push({nx,ny});
                    group[nx][ny]=group[x][y];
                }
            }
        }
    }
    
    calcTouch(); // 맞닿는 변 개수 계산
    int score=0;
    for(int i=1;i<groupCnt;i++){
        for(int j=i+1;j<=groupCnt;j++){
            score += (groupSize[i]+groupSize[j]) * (touch[i][j]+touch[j][i]) * groupIdx[i] * groupIdx[j];
        }
    }
    return score;
}

void rotate(int x,int y)
{
    int len = (N-1)/2;
    
    int tmp[MAX][MAX]={0,};
    
    for(int i=0;i<len;i++){
        for(int j=0;j<len;j++){
            tmp[j][len-1-i] = map[x+i][y+j];
        }
    }
    
    for(int i=0;i<len;i++){
        for(int j=0;j<len;j++){
            map[x+i][y+j]=tmp[i][j];
        }
    }
    
}
void rotate()
{
    int len = (N-1)/2 + 1;
    
    rotate(0,0);
    rotate(0,len);
    rotate(len,0);
    rotate(len,len);

    int tmp[MAX]={0,};
    len-=1;
    
    for(int i=0;i<len;i++)  tmp[i] = map[i][len];
    for(int i=0;i<len;i++)  map[i][len] = map[len][N-1-i];
    for(int i=0;i<len;i++)  map[len][N-1-i]= map[N-1-i][len];
    for(int i=0;i<len;i++)  map[N-1-i][len]=map[len][i];
    for(int i=0;i<len;i++)  map[len][i]=tmp[i];

}

int main(void)
{
    cin >> N;
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++)    cin >> map[i][j];
    }
    int score =0;
    
    score += calcScore();
    
    for(int i=0;i<3;i++){
        rotate();
        score += calcScore();
    }
    cout << score;
    return 0;
}

'알고리즘' 카테고리의 다른 글

[코드트리] 동전 챙기기 ( C++)  (0) 2022.10.15
[코드트리] 나무박멸 (C++)  (0) 2022.10.12
[코드트리] 술래잡기 (C++)  (0) 2022.10.10

+ Recent posts