hyelie
hyelie
Hyeil Jeong
       
글쓰기    관리    수식입력
  • 전체보기 (495)
    • PS (283)
      • Algorithm (28)
      • PS Log (244)
      • Contest (6)
      • Tips (5)
    • Development (52)
      • Java (14)
      • Spring (23)
      • SQL (2)
      • Node.js (2)
      • Socket.io (3)
      • Study (4)
      • Utils (4)
    • DevOps (36)
      • Git (5)
      • Docker (4)
      • Kubernetes (2)
      • GCP (3)
      • Environment Set Up (8)
      • Tutorial (12)
      • Figma (2)
    • CS (74)
      • OOP (7)
      • OS (24)
      • DB (2)
      • Network (24)
      • Architecture (0)
      • Security (2)
      • Software Design (0)
      • Parallel Computing (15)
    • Project (15)
      • Project N2T (5)
      • Project ASG (0)
      • Project Meerkat (1)
      • Model Checking (7)
      • Ideas (2)
    • 내가 하고싶은 것! (34)
      • Plan (16)
      • Software Maestro (10)
      • 취준 (8)
hELLO · Designed By 정상우.
hyelie

hyelie

PS/PS Log

22.06.14. 풀었던 문제들

1. 블록 이동하기

어제 시간 없어서 못 풀었던 문제 풀었다. 전체적으로 구현이 귀찮은 문제였다. 신경 쓸 것도 많았고.

로직 자체는 간단한 BFS이지만

​

1) visited 배열 - 로봇의 위치는 점 2개로 이루어지기 때문에 점 2개를 이용해서 중복 검사를 할 수 있게 해야 했기 때문에 ppiipii를 항상 정렬한 상태로 유지했다.

2) 이동 가 / 불 여부 - 현재 위치 (r, c), (r', c') 기준으로 어디로 이동할 수 있는가?를 조금 생각해 주어야 했다.

a) 직선 이동하는 경우 - 위 / 아 / 왼 / 오 - 모두 다 범위 안이고 0이어야 이동할 수 있음. 이건 쉽지만

b) 회전 이동하는 경우 - (r, c)을 축으로 90도 - 이게 귀찮았다. 물론 이동 후 위치도 0이어야 이동 가능하겠지?

가로 : (r, c)와 (r', c')에서 축이 (r, c)인 경우

(r+1, c)와 (r-1, c)로 갈 수 있음

(r+1, c)로 가는 경우 : (r+1, c')가 1인지 검사해야 함

(r-1, c)로 가는 경우 : (r-1, c')가 1인지 검사해야 함

세로 : (r, c)와 (r', c')에서 축이 (r, c)인 경우

(r, c+1)와 (r, c-1)로 갈 수 있음

(r, c+1)로 가는 경우 : (r', c+1)가 1인지 검사해야 함

(r, c-1)로 가는 경우 : (r', c-1)가 1인지 검사해야 함

​

// 블록 이동하기

#include <string>
#include <vector>
#include <set>
#include <queue>
#include <iostream>

using namespace std;

int N;
typedef pair<int, int> pii;
typedef pair<pii, pii> ppiipii; //drone 위치

bool cmp(pii &a, pii &b){
    if(a.first == b.first){
        return a.second < b.second;
    }
    return a.first < b.first;
}

void sort_ppiipii(ppiipii &a){
    if(!cmp(a.first, a.second)){
        pii temp = a.first;
        a.first = a.second;
        a.second = temp;
        return;
    }
    return;
}

void rotate(vector<vector<int>>& board, pii mov, pii axis, bool isVertical, vector<ppiipii>& result){
    if(isVertical){ // 세로
        if(axis.second + 1 < N && board[mov.first][axis.second+1] == 0 && board[axis.first][axis.second + 1] == 0){
            result.push_back({axis, {axis.first, axis.second + 1}});
        }
        if(axis.second - 1 >= 0 && board[mov.first][axis.second-1] == 0 && board[axis.first][axis.second - 1] == 0){
            result.push_back({axis, {axis.first, axis.second - 1}});
        }
    }
    else{ // 가로
        if(axis.first + 1 < N && board[axis.first + 1][mov.second] == 0 && board[axis.first + 1][axis.second] == 0){
            result.push_back({axis, {axis.first + 1, axis.second}});
        }
        if(axis.first - 1 >= 0 && board[axis.first - 1][mov.second] == 0 && board[axis.first - 1][axis.second] == 0){
            result.push_back({axis, {axis.first - 1, axis.second}});
        }
    }
}
/*
 가로 : (r, c)와 (r', c')에서 축이 (r, c)인 경우
            (r+1, c)와 (r-1, c)로 갈 수 있음
            (r+1, c)로 가는 경우 : (r+1, c')가 1인지 검사해야 함
            (r-1, c)로 가는 셩우 : (r-1, c')가 1인지 검사해야 함
 세로 : (r, c)와 (r', c')에서 축이 (r, c)인 경우
            (r, c+1)와 (r, c-1)로 갈 수 있음
            (r, c+1)로 가는 경우 : (r', c+1)가 1인지 검사해야 함
            (r, c-1)로 가는 경우 : (r', c-1)가 1인지 검사해야 함*/

vector<ppiipii> moveablePosition(vector<vector<int>>& board, ppiipii &cur_position){
    vector<ppiipii> result;
    pii blue = cur_position.first, red = cur_position.second;
    if(blue.first + 1 < N && board[blue.first + 1][blue.second] == 0 && red.first + 1 < N && board[red.first + 1][red.second] == 0){ // 하
        result.push_back({{blue.first+1, blue.second}, {red.first+1, red.second}});
    }
    if(blue.first - 1 >= 0 && board[blue.first - 1][blue.second] == 0 && red.first - 1 >= 0 && board[red.first - 1][red.second] == 0){ // 상
        result.push_back({{blue.first-1, blue.second}, {red.first-1, red.second}});
    }
    if(blue.second + 1 < N && board[blue.first][blue.second + 1] == 0 && red.second + 1 < N && board[red.first][red.second + 1] == 0){ // 우
        result.push_back({{blue.first, blue.second + 1}, {red.first, red.second + 1}});
    }
    if(blue.second - 1 >= 0 && board[blue.first][blue.second - 1] == 0 && red.second - 1 >= 0 && board[red.first][red.second - 1] == 0){ // 좌
        result.push_back({{blue.first, blue.second - 1}, {red.first, red.second - 1}});
    }
    
    bool isVertical = blue.second == red.second;
    rotate(board, blue, red, isVertical, result);
    rotate(board, red, blue, isVertical, result);
    for(int i = 0; i<result.size(); i++){
        sort_ppiipii(result[i]);
    }
    return result;
}

bool isArrive(ppiipii& cur_position){
    pii blue = cur_position.first, red = cur_position.second;
    if((blue.first == N-1 && blue.second == N-1) || (red.first == N-1 && red.second == N-1)) return true;
    else return false;
}

int solution(vector<vector<int>> board) {
    N = board.size();
    
    ppiipii drone = {{0, 0}, {0, 1}}; // .first : 첫 번째 점, .second : 두 번째 점
    
    set<ppiipii> visited;
    sort_ppiipii(drone);
    visited.insert(drone);
    
    queue<pair<ppiipii, int>> q; // .first : 현재 드론 위치 ppiipii, .second : 해당 위치의 dist
    q.push({drone, 0});
    
    while(!q.empty()){
        ppiipii cur_position = q.front().first;
        int cur_dist = q.front().second;
        
        /*cout<<"점, dist : "<<cur_dist<<endl;
        cout<<"blue : "<<cur_position.first.first<<", "<<cur_position.first.second<<endl;
        cout<<"red : "<<cur_position.second.first<<", "<<cur_position.second.second<<endl;
        cout<<endl;*/
        
        q.pop();
        vector<ppiipii> moveable = moveablePosition(board, cur_position);
        for(ppiipii& m : moveable){
            
            if(isArrive(m)){
                return cur_dist + 1;
            }
            
            sort_ppiipii(m);
            
            if(visited.find(m) == visited.end()){ // not visited
                visited.insert(m);
                q.push({m, cur_dist + 1});
            }
        }
    }
    return -1;
}

/*

BFS인데 신경 쓸 게 많은...
1) visited 배열 - 현재 로봇의 위치는 점 2개로 이루어지니 이들의 중복 검사를 할 수 있게 해야 함
2) 이동하는 경로 - 현재 위치 (r, c), (r', c') 기준으로 어디로 이동할 수 있는가?
  a) 직선 이동하는 경우 - 위 / 아 / 왼 / 오 - 모두 다 범위 안이고 0이어야 이동할 수 있음
  b) 회전 이동하는 경우 - (r, c)을 축으로 90도

 가로 : (r, c)와 (r', c')에서 축이 (r, c)인 경우
            (r+1, c)와 (r-1, c)로 갈 수 있음
            (r+1, c)로 가는 경우 : (r+1, c')가 1인지 검사해야 함
            (r-1, c)로 가는 셩

 

 

2. 매칭 점수

string의 find 함수를 이용하면 너무너무 쉽게 풀 수 있다. string.find(target, start_index) == string::npos 인 경우에는 string의 start_index부터 target을 찾아서 string::npos면 못 찾은 것이다. 이거 정리해 보자.

일단 알고리즘의 경우에는 page를 받아서 해당 page에서 뽑을 수 있는 모든 정보(해당 page 이름, 참조하는 외부 링크 vector 및 그 숫자(href 개수), 해당 page의 기본 점수(word에 해당하는 문자 검사 - word를 찾으면 앞뒤로 alphabet이 아닌지 확인해야 한다) 등을 뽑아 구조체에 넣었다. 이렇게 첫 번째 for문을 돌리고 mapper를 만들어 이름-index mapping을 했다. 이후는 쉽다. page의 href vector마다 (basic 점수 / 참조 개수)만큼 더해주고, 정렬하면 끝이다.

// 매칭 점수

#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>

using namespace std;

struct webdata{
    int index, basic_point, num_external_link;
    double link_point;
    string pagename;
    vector<string> hrefs;
};

bool cmp(webdata &a, webdata &b){
    if(a.link_point + a.basic_point == b.link_point + b.basic_point){
        return a.index < b.index;
    }
    else return a.link_point + a.basic_point > b.link_point + b.basic_point;
}

webdata summary(string word, string page){
    webdata wd; wd.index = wd.basic_point = wd.num_external_link = wd.link_point = 0;
    wd.pagename = "";
    
    // 해당 page 이름 뽑기
    string metatag = "<meta property=\"og:url\" content=\"";
    int pagename_start_idx = page.find(metatag) + metatag.length();
    int metatag_end_idx = page.find("\"/>", pagename_start_idx);
    wd.pagename = page.substr(pagename_start_idx, metatag_end_idx - pagename_start_idx);
    
    // 해당 page가 참조하는 외부 링크(및 그 수) 뽑기
    int hreftag_start_idx = 0, hreftag_end_idx = 0;
    string hreftag = "<a href=\"";
    while(1){
        hreftag_start_idx = page.find(hreftag, hreftag_end_idx);
        if(hreftag_start_idx == string::npos) break;
        hreftag_start_idx += hreftag.length();
        hreftag_end_idx = page.find("\">", hreftag_start_idx);
        wd.num_external_link++;
        wd.hrefs.push_back(page.substr(hreftag_start_idx, hreftag_end_idx - hreftag_start_idx)); // 참조하는 링크
    }
    
    // 해당 page의 기본 점수(word에 해당하는 문자열) 뽑기
    for(char& c : page) c = tolower(c);
    for(char& c : word) c = tolower(c);
    int word_start_idx = 0, wordsize = word.size(), pagesize = page.size();
    while(1){
        word_start_idx = page.find(word, word_start_idx);
        if(word_start_idx == string::npos) break;
        if(word_start_idx + wordsize >= pagesize
           || (word_start_idx - 1 >= 0 && !isalpha(page[word_start_idx - 1]) && word_start_idx + wordsize < pagesize && !isalpha(page[word_start_idx + wordsize]))){
            wd.basic_point++;
        }
        word_start_idx++;
    }
    
    return wd;
}

int solution(string word, vector<string> pages) {
    map<string, int> mapper; // mapper[string] : string에 해당하는 pages index
    vector<vector<int>> adjacent(21, vector<int>(21, 0)); // adjacent[i][j] : i에서 j를 호출하는 갯수
    vector<webdata> v(pages.size());
    
    for(int i = 0; i<pages.size(); i++){
        webdata wd = summary(word, pages[i]);
        wd.index = i;
        mapper[wd.pagename] = i;
        v[i] = wd;
    }
    
    for(int i = 0; i<v.size(); i++){
        double link_point = (double)v[i].basic_point / (double)v[i].num_external_link;
        for(string& h : v[i].hrefs){
            if(mapper.find(h) != mapper.end())
                v[mapper[h]].link_point += link_point;
        }
        
        cout<<endl;
    }
    
    sort(v.begin(), v.end(), cmp);
    
    return v[0].index;
}

/*

기본 점수 : text 중 검색어가 등장하는 횟수(대소문자 무시)
외부 링크 수 : 해당 페이지에서 다른 웹페이졸 연결된 링크 개수
링크 점수 : 해당 웹페이지로 링크걸린 다른 웹페이지의 기본점수 / 해당 웹페이지의 외부 링크 수의 총 합

*/

'PS > PS Log' 카테고리의 다른 글

22.06.16. 풀었던 문제들  (0) 2022.06.23
22.06.15. 풀었던 문제들  (0) 2022.06.23
22.06.13. 풀었던 문제들  (0) 2022.06.23
22.06.12. 풀었던 문제들  (0) 2022.06.23
22.06.11. 풀었던 문제들  (0) 2022.06.23
    hyelie
    hyelie

    티스토리툴바