<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>min_gi1123.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 24 Feb 2024 16:55:07 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>min_gi1123.log</title>
            <url>https://velog.velcdn.com/images/min_gi1123/profile/60640dbe-2b90-4f00-9fa5-ef361bf58b80/image.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. min_gi1123.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/min_gi1123" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[c++] 백준 1561 놀이공원 (이분 탐색 / binary search)]]></title>
            <link>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-1561-%EB%86%80%EC%9D%B4%EA%B3%B5%EC%9B%90</link>
            <guid>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-1561-%EB%86%80%EC%9D%B4%EA%B3%B5%EC%9B%90</guid>
            <pubDate>Sat, 24 Feb 2024 16:55:07 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/1561">https://www.acmicpc.net/problem/1561</a></p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/164a27d2-9048-4aa1-b2c7-d1494bfed6fc/image.png" alt=""></p>
<h3 id="solution">solution</h3>
<p>main 함수에서 while 문을 돌면서 <strong>이분탐색</strong>을 수행한다.
이분탐색을 통해 얻은 최적의 운영시간을 이용하여 마지막 아이가 타러 들어가는 놀이기구 번호를 구해준다.
<span style="color: gray"> -&gt; 이 부분에서 결과괎을 어떻게 사용하는지에 대해 블로그를 참고 (<a href="https://baebalja.tistory.com/m/158">https://baebalja.tistory.com/m/158</a>) </span></p>
<p><strong>시간복잡도</strong>
O(log(놀이기구 하나의 운행 시간 * 인원 수의 최대 값))</p>
<h3 id="check-함수">check 함수</h3>
<p>해당 운행시간으로 놀이기구를 운전 할 때, 탑승할 수 있는 인원수를 계산</p>
<pre><code class="language-cpp">bool check(long long mid) {
    ll cnt = q;
    for (int i = 0; i &lt; v.size(); i++) {
        cnt += mid / v[i];
    }
    return cnt &gt;= n;
}</code></pre>
<h3 id="전체-코드">전체 코드</h3>
<pre><code class="language-cpp">#include &lt;climits&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;
using namespace std;

vector&lt;int&gt; v; // 놀이기구의 운행시간을 저장하는 벡터
vector&lt;int&gt; result1; // 결과 벡터 1
vector&lt;int&gt; result2; // 결과 벡터 2
typedef long long ll; // long long 자료형의 별칭 설정

ll l, h, n, q; // 이분탐색의 범위와 입력 변수 선언

// 주어진 운행시간(mid)으로 놀이기구를 탈 수 있는지 확인하는 함수
bool check(long long mid) {
    ll cnt = q; // cnt 변수에 초기 운행 횟수 할당
    for (int i = 0; i &lt; v.size(); i++) { // 모든 놀이기구에 대해 반복
        cnt += mid / v[i]; // 주어진 시간 동안 각 놀이기구의 운행 횟수 더하기
    }
    return cnt &gt;= n; // 놀이기구 운행 횟수가 요구된 인원 수 이상인지 확인
}

int main() {
    l = 1; // 이분탐색의 시작 범위
    h = 60000000000; // 이분탐색의 끝 범위 (놀이기구 하나의 운행시간 * 인원수의 최대값)
    cin &gt;&gt; n; // 인원 수 입력
    cin &gt;&gt; q; // 놀이기구 수 입력
    for (int i = 0; i &lt; q; i++) { // 모든 놀이기구의 운행시간 입력
        int a;
        cin &gt;&gt; a;
        v.push_back(a); // 놀이기구의 운행시간 벡터에 추가
    }
    if (n &lt;= q) { // 인원 수가 놀이기구 수와 같거나 작은 경우
        cout &lt;&lt; n; // 인원 수 출력 후 프로그램 종료
        return 0;
    }
    ll time = 0; // 최적 운행시간 초기화
    while (l &lt;= h) { // 이분탐색 수행
        long long mid = (l + h) / 2; // 중간 값 설정
        if (check(mid)) { // 운행시간이 충분한 경우
            h = mid - 1; // 더 작은 운행시간을 탐색하기 위해 범위 갱신
            time = mid; // 현재 운행시간 저장
        } else {
            l = mid + 1; // 운행시간이 부족한 경우, 더 큰 운행시간을 탐색하기 위해 범위 갱신
        }
    }
    ll ch = q; // 이전 운행 횟수로 초기화
    for (int i = 0; i &lt; q; i++) { // time-1초에 타러간 아이들의 수 계산
        ch += (time - 1) / v[i];
    }
    for (int i = 0; i &lt; q; i++) { // time초에 타러가는 아이들의 수 갱신
        if (time % v[i] == 0) ch++;
        if (ch == n) { // 마지막 아이가 타러 들어가는 놀이기구 번호 출력
            cout &lt;&lt; i + 1 &lt;&lt; &quot;\n&quot;;
            break;
        }
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] 백준 2565 전깃줄 (dp / 최장 증가 부분 수열 / LIS)]]></title>
            <link>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-2565-%EC%A0%84%EA%B9%83%EC%A4%84</link>
            <guid>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-2565-%EC%A0%84%EA%B9%83%EC%A4%84</guid>
            <pubDate>Sat, 24 Feb 2024 16:43:51 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/2565">https://www.acmicpc.net/problem/2565</a></p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/eff268fe-eb1e-425d-a62c-633066f7f997/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/d478b366-36c6-4c56-9a89-37d16048ef38/image.png" alt=""></p>
<h3 id="솔루션">솔루션</h3>
<p>왼쪽 기준 오름차순으로 정렬했을때, 오른쪽 값이 이전보다 <strong>커야된다</strong>는 점에서 LIS임을 캐치 할 수 있었다.
정렬 후 오른쪽 기준의 최장 증가 부분 수열을 구한 후, 전봇대의 개수에서 빼주면 최소한으로 제거할 수 있는 전선의 개수를 구할 수 있다.
<span style="color: gray"> 가장 긴 증가하는 부분 수열 문제와 코드가 아주 유사하다. </span></p>
<h3 id="전체코드">전체코드</h3>
<pre><code class="language-cpp">#include &lt;algorithm&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;

using namespace std;

int n, dp[105];
vector&lt;pair&lt;int, int&gt;&gt; v;

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

    cin &gt;&gt; n;
    for (int i = 0; i &lt; n; i++) {
        int a, b;
        cin &gt;&gt; a &gt;&gt; b;
        v.push_back({a, b});
    }

    fill(dp, dp + n, 1);
    sort(v.begin(), v.end());

    for (int i = 0; i &lt; n; i++) {
        for (int j = 0; j &lt; i; j++) {
            if (v[i].second &gt; v[j].second &amp;&amp; dp[i] &lt; dp[j] + 1) {
                dp[i] = dp[j] + 1;
            }
        }
    }

    int res = 0;
    for (int i = 0; i &lt; n; i++) {
        if (res &lt; dp[i]) res = dp[i];
    }
    cout &lt;&lt; n - res;

    return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] 백준 14002 가장 긴 증가하는 부분 수열 4 (최장 증가 부분 수열 / LIS / Longest Increasing)]]></title>
            <link>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-14002-%EA%B0%80%EC%9E%A5-%EA%B8%B4-%EC%A6%9D%EA%B0%80%ED%95%98%EB%8A%94-%EB%B6%80%EB%B6%84-%EC%88%98%EC%97%B4-4</link>
            <guid>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-14002-%EA%B0%80%EC%9E%A5-%EA%B8%B4-%EC%A6%9D%EA%B0%80%ED%95%98%EB%8A%94-%EB%B6%80%EB%B6%84-%EC%88%98%EC%97%B4-4</guid>
            <pubDate>Sat, 24 Feb 2024 16:37:33 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/14002">https://www.acmicpc.net/problem/14002</a></p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/3d09d7c5-2a6e-4af4-b0a4-1ff3dfa9d6d0/image.png" alt=""></p>
<h3 id="lis-longest-increasing-subsequence">LIS (Longest Increasing Subsequence)</h3>
<blockquote>
<p>주어진 &#39;수열&#39; 에서 일부 원소를 뽑아내어 새로만든 수열이 &#39;부분 수열&#39;
이 수열이 &#39;오름차순&#39; 인 수열이 &#39;증가하는 부분 수열&#39; 이 된다.
만들 수 있는 오름차순 수열 중, &#39;가장 긴&#39; 수열이 LIS가 된다.</p>
</blockquote>
<p>가장 긴 증가하는 부분수열 시리즈의 코드와 거의 유사하나, 가장 증가하는 부분 수열의 길이 + 수열을 출력해야한다.</p>
<p>수열을 저장하고 출력하는 부분의 코드가 추가되었다.</p>
<h3 id="lis-코드">LIS 코드</h3>
<p>arr배열을 탐색하며 증가 수열이 가능한 경우 dp배열을 갱신시켜준다.</p>
<pre><code class="language-cpp">for (int i = 0; i &lt; n; i++) {
    for (int j = 0; j &lt; i; j++) {
        if (arr[i] &gt; arr[j] &amp;&amp; dp[i] &lt; dp[j] + 1) {
            dp[i] = dp[j] + 1;
        }
    }
}</code></pre>
<h3 id="수열-저장">수열 저장</h3>
<p>최장길이인 temp값을 --시켜주면서 해당되는 값을 벡터에 저장</p>
<pre><code class="language-cpp">int temp = res;
for (int i = n - 1; i &gt;= 0; i--) {
    if (temp == 0) break;
    if (dp[i] == temp) {
        v.push_back(arr[i]);
        temp--;
    }
}</code></pre>
<p>후 벡터를 뒤에서 부터 출력해 주었습니다.</p>
<h3 id="전체코드">전체코드</h3>
<pre><code class="language-cpp">#include &lt;algorithm&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;

using namespace std;

int n, arr[1005], dp[1005];
vector&lt;int&gt; v;

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

    cin &gt;&gt; n;
    for (int i = 0; i &lt; n; i++) cin &gt;&gt; arr[i];
    fill(dp, dp + n, 1);

    for (int i = 0; i &lt; n; i++) {
        for (int j = 0; j &lt; i; j++) {
            if (arr[i] &gt; arr[j] &amp;&amp; dp[i] &lt; dp[j] + 1) {
                dp[i] = dp[j] + 1;
            }
        }
    }

    int res = 0;
    for (int i = 0; i &lt; n; i++) {
        if (dp[i] &gt; res) res = dp[i];
    }
    int temp = res;
    for (int i = n - 1; i &gt;= 0; i--) {
        if (temp == 0) break;
        if (dp[i] == temp) {
            v.push_back(arr[i]);
            temp--;
        }
    }

    cout &lt;&lt; res &lt;&lt; &quot;\n&quot;;
    for (int i = v.size() - 1; i &gt;= 0; i--) cout &lt;&lt; v[i] &lt;&lt; &quot; &quot;;

    return 0;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] 백준 16434 드래곤 앤 던전  (이분 탐색 / binary search)]]></title>
            <link>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-16434-%EB%93%9C%EB%9E%98%EA%B3%A4-%EC%95%A4-%EB%8D%98%EC%A0%84</link>
            <guid>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-16434-%EB%93%9C%EB%9E%98%EA%B3%A4-%EC%95%A4-%EB%8D%98%EC%A0%84</guid>
            <pubDate>Sat, 24 Feb 2024 16:26:41 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/16434">https://www.acmicpc.net/problem/16434</a></p>
<img src = "https://velog.velcdn.com/images/min_gi1123/post/88c15faa-1bef-4d71-b94c-c276c96a0dbf/image.png">
<img src = "https://velog.velcdn.com/images/min_gi1123/post/c694d746-7fc2-4235-9e3a-882ca889cf9b/image.png">

<h3 id="binary-search--이분탐색">Binary Search / 이분탐색</h3>
<blockquote>
<p>오름차순의 값 left ~ right 사이의 중간위치 mid를 구하여 array[mid]의 값과 타겟을 비교한다.
-&gt; 타겟이 mid의 값보다 작다면 : right = mid
-&gt; 타겟이 mid의 값보다 크다면 : left = mid + 1;
시간복잡도 O(logN)</p>
</blockquote>
<h3 id="이분탐색인-이유">이분탐색인 이유</h3>
<p>입력 조건 : 방의 개수 N (1 ≤ N  ≤ 123,456)
HMaxHP 의 값을 1부터 최대값까지 계산하면 시간초과가 난다.</p>
<p>left, right 값 설정하는 과정에서 HMaxHP의 최댓값이 아주 크다는 사실을 알게되었다.
left를 1로, right를 1e12 로 설정해주었더니 right의 값이 부족해서 틀렸습니다를 겪었다. 
right값을 9e18 로 설정하여 여유있게 통과할 수 있었다.</p>
<p>10억이상이면 이분탐색을 쓰라는 글을 본 적이 있었던 것 같기도..</p>
<h3 id="tuple">tuple</h3>
<p>방의 상태, 몬스터의 공격력, 몬스터의 생명력 을 저장하는 tuple을 가진 vector배열을 사용했다.</p>
<pre><code class="language-cpp">typedef tuple&lt;int, int, int&gt; t;
vector&lt;t&gt; v;</code></pre>
<h3 id="check-함수">check 함수</h3>
<p>해당 hp로 용사의 생존 가능을 검사하는 함수</p>
<pre><code class="language-cpp">bool check(long long HP) {
    long long atk = m, hp = HP; // 공격력, 생명력

    for (int i = 0; i &lt; n; i++) {
        int state, ma, mh; // 방의 상태, 몬스터의 공격력, 몬스터의 생명력
        tie(state, ma, mh) = v[i];

        if (state == 1) { // 몬스터
            long long t; // 쓰러트리기까지의 횟수
            if (mh % atk == 0)
                t = mh / atk - 1;
            else
                t = mh / atk;
            hp -= ma * t;

            if (hp &lt;= 0) return false; // 생존 불가능
        } else { // 포션
            atk += ma; // 공격력 증가
            hp = min(HP, hp + mh); // 생명력 회복
        }
    }

    return true; 
}</code></pre>
<h3 id="전체코드">전체코드</h3>
<pre><code class="language-cpp">#include &lt;algorithm&gt;
#include &lt;iostream&gt;

using namespace std;

typedef tuple&lt;int, int, int&gt; t;

int n, m;
vector&lt;t&gt; v;
long long res;

bool check(long long HP) {
    long long atk = m, hp = HP;

    for (int i = 0; i &lt; n; i++) {
        int state, ma, mh;
        tie(state, ma, mh) = v[i];

        if (state == 1) {
            long long t;

            if (mh % atk == 0)
                t = mh / atk - 1;
            else
                t = mh / atk;

            hp -= ma * t;
            if (hp &lt;= 0) return false;
        } else {
            atk += ma;
            hp = min(HP, hp + mh);
        }
    }

    return true;
}

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

    cin &gt;&gt; n &gt;&gt; m;
    for (int i = 0; i &lt; n; i++) {
        int a, b, c;
        cin &gt;&gt; a &gt;&gt; b &gt;&gt; c;
        v.push_back({a, b, c});
    }

    long long left = 1, right = 1e18;
    while (left &lt;= right) {
        long long mid = (left + right) / 2;

        if (check(mid)) {
            right = mid - 1;
            res = mid;
        } else {
            left = mid + 1;
        }
    }
    cout &lt;&lt; res;

    return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[2024 상반기 ICT 인턴십 합격 후기]]></title>
            <link>https://velog.io/@min_gi1123/2024-%EC%83%81%EB%B0%98%EA%B8%B0-ICT-%EC%9D%B8%ED%84%B4%EC%8B%AD-%ED%95%A9%EA%B2%A9-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@min_gi1123/2024-%EC%83%81%EB%B0%98%EA%B8%B0-ICT-%EC%9D%B8%ED%84%B4%EC%8B%AD-%ED%95%A9%EA%B2%A9-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Wed, 21 Feb 2024 13:14:31 GMT</pubDate>
            <description><![CDATA[<p>2024년 상반기 ICT 인턴십 지원 후기를 기록하고자한다.</p>
<p>일단 나는 2월 2일 마감인데 1월 31일 저녁에 알게되었다..</p>
<p>프론트엔드를 모집하는 기업은 40개정도였는데 다음과 같은 순위로 기업을 추렸다.</p>
<blockquote>
<ol>
<li>자율 출퇴근제</li>
<li>점심 식대 지원</li>
<li>개발직의 규모 및 유명세</li>
</ol>
</blockquote>
<p>M사, R사, A사 으로 선택했다.
무경력주제에 너무 과분한 기업만 골랐다.</p>
<h2 id="이력서-자기소개서-포트폴리오">이력서, 자기소개서, 포트폴리오</h2>
<p>이력서는 홈페이지에서 제공해주는 이력서 양식을 그대로 활용했다.
학점이랑 전공과목 성적을 기제하는데 민망했다.. 어쩌겠냐만은 하하</p>
<p>자기소개서는 아래와 같은 내용으로 작성하였다.</p>
<blockquote>
<p>지원 동기
본인의 강점
기술적 역량</p>
</blockquote>
<p>포트폴리오는 다른분의 지원후기를 참고하여 노션 포트폴리오를 하나 만들어서 이력서에 첨부했다. 최대한 나를 표현하고자 노력했다.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/a2bd83f1-a2c3-4c88-af4a-7b18863121ba/image.gif" alt="포폴gif"></p>
<blockquote>
<p>소개
수상경력 및 대외활동
기술스택
프로젝트 설명
목표 </p>
</blockquote>
<h2 id="코테">코테</h2>
<p>지원한 3기업 모두 코테 점수를 봤다.
해커랭크에서 6시간동안 5문제를 푸는 방식이었다.
나는 2시간 안넘기고 5문제를 다 해결할 수 있었다!!
문제는 전부 영어였는데 크롬 자동 번역 + 눈치로 풀었다.</p>
<h2 id="서류">서류</h2>
<p>서류 및 면접이 7일<del>16일동안 완료되는 일정이었다.
9일</del>12일이 설연휴라 피말라가며 기다렸다.
감사하게도 두 기업에서 면접 연락을 주셨다.</p>
<p><strong>A사 : **<span style="color: #c02034"></strong>서류 불합격**</span>
7일 ict 홈페이지에 들어가서 불합격 사실을 알게 되었다.
첫 결과부터 서류떨이라 마음이 좋지 못했다..</p>
<p><strong>M사 : **<span style="color: #88b04b"></strong>서류 합격**</span>
8일 저녁 이메일로 연락이 왔다! 원피스보다가 깜짝 놀라서 뒤집어졌다.
바들바들 떨면서 면접 날짜를 지정했다.</p>
<p><strong>R사 : **<span style="color: #88b04b"></strong>서류 합격**</span>
13일 점심 문자로 연락을 받았다! 비대면 30분 면접을 진행한다고 했다.
면접 시간대가 모두 극 아침이었다 ㅜㅜ</p>
<h2 id="면접">면접</h2>
<p><strong>M사</strong>
본사에서 40분가량 진행되었고, 2:1 면접이었다.
면접 시간 전, 대기하는동안 면접키트도 받았다. (물, 핸드크림 등등)
이 기업의 면접 후기를 검색했을때 인성면접을 본 후기가 많아서 인성면접을 준비해갔는데 기술질문만 받았다. </p>
<p>제출한 포트폴리오를 기반으로 아주 자세한 질문들을 주셨다!
면접분위기는 아주 좋았어서 기분좋게 면접보고 나왔다.
35분가량은 질문을 받고, 10분가량은 내가 질문을 하는 시간을 가졌다.</p>
<p>마지막으로 입사한다면 어느 파트에서 일하고 싶은지도 여쭈어주셨다.
면접 보는내내 꼭 붙고싶다는 생각을 오만번정도 했다.</p>
<blockquote>
<p><strong>면접 키워드</strong>
타입스크립트, 컴포넌트 재사용, 알고리즘, 클라이언트 최적화, SSR, SSG</p>
</blockquote>
<p>*<em>R사 *</em>
이른 아침 비대면으로 30분가량 진행되었다. 1:1 면접이었다.
자기소개와 가장 내세울 프로젝트의 소개 후 질문들을 받았다.
전체적으로 내 이력서(수상경력, 대외활동)만 보고 질문해주시는 느낌이었다.
음,,, 그리고 학점이 낮은 이유를 질문해주셨다. (조금 공격적인 질문일 수 있는데~ 로 시작해주셔서 마음의 준비를 할 수 있었다.)</p>
<p>25분 질문받고, 5분정도 내가 질문하는 시간을 가졌는데, 학점 낮은 나를 왜 서류통과 시켰는지 질문드렸다. (이후 면접에서는 안그래야겠다) 
<span style="color: gray"> 내 스택이 기업과 fit하고 코테 만점을 좋게 보셨다고 하셨다.</span></p>
<p>아침이기도하고 버벅거린 부분들이 있어 아쉬운 면접이었다.. </p>
<blockquote>
<p><strong>면접 키워드</strong>
실시간 통신, 소켓, 이미지 최적화, 컴포넌트 재사용</p>
</blockquote>
<h2 id="결과">결과</h2>
<p><strong>R사 : **<span style="color: #c02034"></strong>면접 불합격**</span>
16일 점심즈음 ict 홈페이지에서 불합격 사실을 확인할 수 있었다. 면접보는내내 최종합은 어렵겠다는 생각을 하기는했지만,, 심장이 뚝 떨어지는 느낌이었다 ㅜㅜ</p>
<p><strong>M사 : **<span style="color: #88b04b"></strong>면접 합격**</span>
16일 저녁, 면접 전형이 끝난 시간 이후에 홈페이지에서 면접 합격을 확인할 수 있었다!!!!!!
M사 하나남은 상황이었는데 마지막에 합격 뜨자마자 숨 한번 쉬고 다시 확인했다!!!!!!</p>
<br/>

<p>19일에 기업 확정 버튼이 생기자마자 M사로 확정했다.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/f9897037-8297-4b1d-94a3-890249a61f9d/image.png" alt="최종합격"></p>
<h2 id="회고">회고</h2>
<p>내 첫 인턴을 유명하기도하고 프론트로써 많이 성장할 수 있는 M사에서 일하게 되었다니 진짜 꿈만같다!!!!!!!!!!!!</p>
<p>4학년 1학기를 알찬 인턴생활로 채워보도록 노력하겠다.</p>
<p>열심히 해볼게요 아자아자!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023 프로젝트 모음]]></title>
            <link>https://velog.io/@min_gi1123/2023-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%AA%A8%EC%9D%8C</link>
            <guid>https://velog.io/@min_gi1123/2023-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%AA%A8%EC%9D%8C</guid>
            <pubDate>Sat, 13 Jan 2024 13:32:17 GMT</pubDate>
            <description><![CDATA[<p>2023년을 함께한 프로젝트를 기제하고자 한다.</p>
<h2 id="미니게임천국">미니게임천국</h2>
<blockquote>
<p>미니게임천국 컨셉의 웹 게임 프로젝트
2023.02 ~ 2023.06</p>
</blockquote>
<p><img src="https://user-images.githubusercontent.com/80528044/228595019-bc3d275a-38a0-4f85-8eea-29a079bc0355.gif" alt="mini_title"></p>
<p><strong>회고</strong>
42칭구들과 시작한 웹게임 프로젝트 !
제대로된 협업이 처음이었고, 프론트가 나 혼자라서 힘들었다..
후반에는 준서님께서 리뷰를 해주셨는데 많이 도움이 되었다.
여러 사정으로 백엔드와의 개발을 마무리하지는 못했다.
아쉽지만 적당히 마무리 하게 되었다.
음 그리고,, 이 때 커밋을 자주 안 하는 아주 나쁜 습관을 가지고 있었는데 이후로는 커밋을 잘 분리해서 올리도록 고쳤다아.</p>
<p><strong>무엇을 얻었나요</strong></p>
<ul>
<li>타입스크립트를 사용 할 수 있게 됨</li>
<li>코드 분리의 중요성을 알게 됨</li>
<li>리뷰의 중요성을 알게 됨</li>
<li>원없이 그림을 그릴 수 있었음 </li>
</ul>
<h2 id="강의가-듣고-싶어서">강의가 듣고 싶어서</h2>
<blockquote>
<p>캠퍼스 맵 및 강의실 길 안내 서비스
2023.03 ~ 2023.06</p>
</blockquote>
<p><img src="https://github.com/SSUpower/SSUpower-Front/assets/80528044/d252d10d-de18-4b12-bb1f-136c0aacb9be" alt="길찾기"></p>
<p><strong>회고</strong>
3학년 1학기 소프트웨어프로젝트 수업
개발이 처음인 친구들을 데리고 깃부터 알려주었다.
내 할 일도 하면서 남의 코드도 봐주고, 백엔드 쪽도 신경써야해서 여러모로 정신 없었다. 내가 1주일 빨리 개발해서, 팀원들이 참고할 샘플을 만든다는 생각으로 진행했다. 다른 팀원이 제대로 하고있는건지 계속 직접 확인해야했고, 컨플릭트도 전부 내가 풀어줬다... 쓰다보니 정신병 걸릴 것 같다.</p>
<p>아쉬운 점은 이런 길찾기 알고리즘을 전부 프론트에서 계산했다는 점.
폴더 구조가 굉장히 별로라는 점.
외에도 자잘한 문제가 많았지만 허허허</p>
<p><strong>무엇을 얻었나요</strong></p>
<ul>
<li>인 내 심</li>
<li>recoil 사용</li>
<li>셀레니움으로 크롤링 하기</li>
</ul>
<h2 id="ft_transcendence">ft_transcendence</h2>
<blockquote>
<p>Ping-Pong 웹 게임
2023.10 ~ 2023.11
2024.01 ~ 리팩터링 진행중</p>
</blockquote>
<table>
<tr>
    <th>  
      <img width="1440" alt="로비" src="https://velog.velcdn.com/images/min_gi1123/post/d66a9609-7179-472b-85cc-9fe869fad259/image.png">
    </th>
    <th>
      <img width="1440" alt="채팅" src="https://velog.velcdn.com/images/min_gi1123/post/2a3a0371-699f-4eff-a77e-d4639fae669c/image.png">
    </th>
</ tr>
<tr>
    <th>
      <img width="1440" alt="마이페이지" src="https://github.com/Transcendence-Animal-Crossing/frontend/assets/80528044/2af57f62-57da-45e4-946f-b2ecada6be37">
   </th>
    <th>   
      <img width="1440" alt="게임" src="https://github.com/Transcendence-Animal-Crossing/frontend/assets/80528044/f75ab728-8993-4991-b14a-1e5ba43deed5">
    </th>
  </ tr>
</table>





<p><strong>회고</strong>
42seoul 6서클 마지막 과제
내가 지금까지 만든 것 중에 젤 기엽게 만듦
42서울 귀여운 트센 top5에 들지 않을까요 ?</p>
<p>서버비를 줄이는 방법에 대해서도 고민했던 것 같다. 
쉬운 방법보다 좋은 방법을 추구하도록 노력했다. </p>
<p>겨울 방학동안 팀원들과 리팩터링하고, 새로운 기능 추가해서 제대로 배포 할 예정 !</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/4bc51b5a-9617-4749-94fa-daba61a55c86/image.png" alt=""></p>
<p><strong>무엇을 얻었나요</strong></p>
<ul>
<li>next.js 사용</li>
<li>next에서 제공하는 next-auth, middleware 등 사용</li>
<li>socket.io 사용</li>
<li>eventEmitter 사용</li>
</ul>
<h2 id="ssuspot">SSUspot</h2>
<blockquote>
<p>위치 기반 사진 SNS
2023.10 ~ 2023.12</p>
</blockquote>
<table>
<tr>
    <th>  
      <img width="1000" alt="사진 1" src="https://velog.velcdn.com/images/min_gi1123/post/7fe3807e-87c1-47f1-a57f-f9180e8b7724/image.png">
    </th>
    <th>
      <img width="1000" alt="사진 2" src="https://velog.velcdn.com/images/min_gi1123/post/a109a668-b52b-44ed-b402-451f30cafc36/image.png">
    </th>
</ tr>
<tr>
    <th>
      <img width="1000" alt="사진 3" src="https://velog.velcdn.com/images/min_gi1123/post/5a1de5f5-ee4f-4642-b629-1ce8ea7783e7/image.png">
   </th>
    <th>   
      <img width="1000" alt="사진 4" src="https://velog.velcdn.com/images/min_gi1123/post/4390d3b3-52fb-4157-b9c6-f95e94b08a8f/image.png">   
    </th>
  </ tr>
</table>



<p><strong>회고</strong>
3학년 2학기 캡스톤 프로젝트 1
만족스럽지는 않지만 어느정도 잘 마무리 했다고 생각한다.
다들 다른 활동 하느라 모두 참여율이 낮았다.
나 또한 트센 하느라 열심히 참여하지 못 하여 아쉽다..
위치 및 메타데이터를 더 이용하였으면 좋았을 것 같다.</p>
<p><strong>무엇을 얻었나요</strong></p>
<ul>
<li>aws 배포</li>
<li>모바일 버젼 개발</li>
</ul>
<hr>
<p>와~ 1년 열심히 했다 ~
좀 더 좋은 구조와 좋은 코드에 대해 공부해야겠다.</p>
<p>내가 무엇을 했고, 어떤 것을 배웠는지 정리 할 필요가 있어 적어보았다.
자소서는 참 어렵다아</p>
<p>이제까지 웹 프로젝트를 회고했으니 아래로 42팀플 회고를 시작하겠다.
트센은 위에 썼으니까 제외한다.</p>
<hr>
<h2 id="minishell">minishell</h2>
<blockquote>
<p>터미널 쉘 프로그램 bash 구현
2022.12 ~ 2023.01 (3주)</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/149ac19b-cf58-4283-9a98-78c5ce236d8b/image.png" alt=""></p>
<p><strong>회고</strong>
42seoul 3서클 과제
<code>ls &gt;&gt; a.txt | grep ae</code> → a.txt에 저장 &amp; 출력 없음
이런 실제 bash를 구현하는 과제였다 진짜 막막했었다.
쉘 걍 터미널 아님 ? -&gt; 이랬었다고
나는 파싱부, 이소현은 실행부를 맡아서 했다. (사실 잡일부임. 입력 토큰별로 관리하고 환경변수 관리하고 시그널 처리하고 명령어 구현하고)
이소현이 자주 아팠음!!! 아래 본인 사진 첨부</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/ea458bc0-11a1-490c-9373-709e7abeab09/image.JPG" alt=""></p>
<p>아 금융권에서 미니셸같은 프로젝트 좋아한다는 소문이 있던데
금융권은 저에게 집중해주시길 바랍니다 감사합니다~</p>
<p><strong>무엇을 얻었나요</strong></p>
<ul>
<li>프로세스의 개념</li>
<li>리다이렉션 및 파이프의 개념</li>
<li>프로세스간의 시그널 처리</li>
<li>lldb, vscode 디버거 사용법</li>
<li>Git 사용법</li>
</ul>
<h2 id="cub_3d">cub_3D</h2>
<blockquote>
<p>RayCasting을 이용한 3D게임 구현
2023.02 (2일컷)</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/11e05c97-47cd-487a-9a4a-42fe156d5e1c/image.png" alt=""></p>
<p><strong>회고</strong>
42seoul 4서클 과제
밤새서 후딱 끝내자! -&gt; 2일컷
남예지 장현진 송승훈과 빠르게 샤샤샥 끝내버렸어요.</p>
<p><strong>무엇을 얻었나요</strong></p>
<ul>
<li>레이캐스팅</li>
<li>벡터</li>
<li>mlx 사용</li>
</ul>
<h2 id="ft_irc">ft_irc</h2>
<blockquote>
<p>실시간 채팅 서비스 서버 구현
2023.07 ~ 2023.08 (3주)</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/7cfde5dd-1ad9-443a-8527-14bf3976b1d1/image.png" alt=""></p>
<p><strong>회고</strong>
42seoul 5서클 과제
조효진 교수님의 네트워크 프로그래밍 수업에서 배운 소켓 api가 큰 도움이 되었다. 그래서 내가 첫 단 커넥션 파트를 맡았다.
약 5분정도 지나면 클라이언트의 연결이 끊기는 현상이 있었는데 Pong 명령어를 만들어주고 네트워크 prefix를 적용해줬더니 해결되었었다 우하하.</p>
<p><strong>무엇을 얻었나요</strong></p>
<ul>
<li>네트워크 계층에 대한 이해</li>
<li>블로킹과 논블로킹, 동기와 비동기</li>
</ul>
<hr>
<p>와 이제 42과제 팀플까지 모두 끝나버렸다~
2023년에 팀플을 참 많이 했네요.
42서울의 팀프로젝트 4개중에 3개를 같이한 이소현과 송승훈에게 수고의 말씀돌립니다~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[42seoul] Philosophers 철학자 키우기 + Bonus]]></title>
            <link>https://velog.io/@min_gi1123/42seoul-Philosophers-%EC%B2%A0%ED%95%99%EC%9E%90-%ED%82%A4%EC%9A%B0%EA%B8%B0-Bonus</link>
            <guid>https://velog.io/@min_gi1123/42seoul-Philosophers-%EC%B2%A0%ED%95%99%EC%9E%90-%ED%82%A4%EC%9A%B0%EA%B8%B0-Bonus</guid>
            <pubDate>Sat, 08 Apr 2023 17:36:38 GMT</pubDate>
            <description><![CDATA[<p>재미있게 했던 과제인 Philosophers 과제에 대해 기제하고자 합니다.
근데 과제 끝낸지 4개월 됨; 그치만 저 보너스도 했어용</p>
<ul>
<li>서브젝트 한글 번역본
<a href="https://github.com/42seoul-translation/subject_ko/blob/master/philosophers/philosophers.ko.md">https://github.com/42seoul-translation/subject_ko/blob/master/philosophers/philosophers.ko.md</a></li>
</ul>
<h2 id="서론">서론</h2>
<ol>
<li>이번학기에 쓰레드 배우면서 뮤텍스랑 세마포어를 보니 반가워서</li>
<li>보너스에 대한 지문이 별로 없어서</li>
<li>다른 분들도 보너스를 하시길 바라며 !</li>
</ol>
<h2 id="dining-philosopher-problem">Dining philosopher problem</h2>
<p>과제 해결을 위해 꼭 알아야하는 내용들! </p>
<ul>
<li>Thread<blockquote>
<p>프로세스 내에서 작업을 실행하는 <code>주체</code>
두개 이상의 쓰레드를 가진 프로세스 = 멀티 쓰레드 프로세스 (multi-threaded process)
프로세스는 메모리 공간을 할당받아 실행되나, 쓰레드는 한 프로세스 안에서 실행되며 쓰레드끼리 <code>같은 힙 공간</code>을 공유함</p>
</blockquote>
</li>
</ul>
<ul>
<li><p>Deadlock (교착상태)</p>
<blockquote>
<p>멀티 쓰레드 프로세스에서 <code>동일한 자원</code>을 여러곳에서 동시에 접근 할 때, 두개의 쓰레드가 서로의 락 해제를 무한정 기다리는 상황
Deadlock 발생 조건 4가지중, 하나라도 충족하지 않으면 데드락이 발생하지 않음! -&gt; 우리는 deadlock을 해결하기위해 mutext와 semaphore를 이용할 것.</p>
</blockquote>
</li>
<li><p>Mutex &amp; Semaphore </p>
<blockquote>
<p>뮤텍스의 접근을 lock, unlock으로 관리 =&gt; <code>하나의 쓰레드</code>만 접근
Semaphore는 <code>접근할 수 있는 수</code>를 지정하여 여러 쓰레드의 접근이 가능
멘데토리 : mutext 이용, 보너스 : semaphore 이용 </p>
</blockquote>
</li>
<li><p>Context Switching (컨텍스트 스위칭)</p>
<blockquote>
<p>여러개의 프로세스가 실행되고 있을 때, 기존에 실행되던 프로세스를 중단하고 다른 프로세스를 실행하는 것.
프로세스를 예시로 들었지만, 실제로 Context가 포괄하는 범위는 넓어용
왜 필요해요 ? : 철학자 쓰레드가 200명정도 된다고 가정했을때, 컨텍스트 스위칭을 발생시켜주어 시간 지연을 최소화합니다. 안 해주면 시간이 밀려서 원래 죽지않아야 할 철학자도 죽습니다.</p>
</blockquote>
</li>
</ul>
<h1 id="mandatory">Mandatory</h1>
<h3 id="로직">로직</h3>
<ol>
<li>입력 파싱</li>
<li>철학자들이 각각의 쓰레드에서 활동하게 함</li>
<li>메인 쓰레드에서 철학자들의 종료 조건을 검사</li>
</ol>
<h3 id="0-구조">0. 구조</h3>
<p>입력 인자를 저장하는 구조체와 각 철학자들이 하나씩 가지고있는 구조체
각각의 철학자들은 모두 입력 구조체의 인자들을 참조 할 수 있음.</p>
<pre><code class="language-c">typedef struct s_arg
{
    int                philo_num; // 철학자 수
    int                life_time; // 철학자 생명 시간
    int                eat_time; // 식사 소요 시간
    int                sleep_time; // 수면 소요 시간
    int                eat_num; // 식사 횟수
    /* pthread_mutex_t     무더기들 중략 */
    int                monitor; // 종료 flag
}    t_arg;

typedef struct s_philo
{
    int            id; // 철학자 넘버
    int            eat_count; // 철학자 식사 횟수
    int            left; // 왼쪽 포크 넘버
    int            right; // 오른쪽 포크 넘버
    long        last_eat; // 마지막 식사 시간
    long        last_time; // 쓰레드의 시작시간 (작명센스 ㅈㅅ)
    pthread_t    thread; // 쓰레드 ID
    t_arg        *arg; // 입력 인자 값
}    t_philo;</code></pre>
<h3 id="1-파싱">1. 파싱</h3>
<p>별 거 없이 argv를 변환하여 넣어준다.
철학자의 식사횟수가 입력으로 들어오는 경우와 들어오지 않는 경우를 분리해주어야한다. 평가를 다녀보니 처리를 따로 해주지않아 쓰레기값이 들어오는 경우들이 있더라</p>
<pre><code class="language-c">int    init_argv(t_arg *arg, int argc, char **argv)
{
    arg-&gt;philo_num = ft_atoi(argv[1]);
    arg-&gt;life_time = ft_atoi(argv[2]);
    arg-&gt;eat_time = ft_atoi(argv[3]);
    arg-&gt;sleep_time = ft_atoi(argv[4]);
    arg-&gt;monitor = 0;
    if (arg-&gt;philo_num &lt;= 0 || arg-&gt;life_time &lt; 0 || \
        arg-&gt;eat_time &lt; 0 || arg-&gt;sleep_time &lt; 0)
        return (1);
    if (argc == 6)
    {
        arg-&gt;eat_num = ft_atoi(argv[5]);
        if (arg-&gt;eat_num &lt;= 0)
            return (1);
    }
    else
        arg-&gt;eat_num = 0;
    return (0);
}</code></pre>
<p>마찬가지로 각각의 철학자들도 초기화 해주어야한다. 설명이 필요없을 것 같아 줄인다.</p>
<pre><code class="language-c">int    init_philo(t_philo **philo, t_arg *arg)
{
    int        i;

    i = 0;
    *philo = malloc(sizeof(t_philo) * arg-&gt;philo_num);
    if (!philo)
        return (1);
    while (i &lt; arg-&gt;philo_num)
    {
        (*philo)[i].id = i + 1;
        (*philo)[i].eat_count = 0;
        (*philo)[i].left = i;
        (*philo)[i].right = (i + 1) % arg-&gt;philo_num;
        (*philo)[i].last_eat = 0;
        (*philo)[i].last_time = 0;
        (*philo)[i].arg = arg;
        i++;
    }
    return (0);
}</code></pre>
<h3 id="2-뮤텍스">2. 뮤텍스</h3>
<p>내가 선언한 뮤텍스들</p>
<pre><code class="language-c">pthread_mutex_t    *fork;
pthread_mutex_t    print;
pthread_mutex_t    mutex_monitor;
pthread_mutex_t    mutex_eat_cnt;
pthread_mutex_t    mutex_last_eat;</code></pre>
<p>아래로는 사용할 뮤텍스 함수들</p>
<pre><code class="language-c">//뮤텍스 생성 함수, 성공하면 0 리턴
int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutex_attr *attr);
// mutex : 뮤텍스 객체
// attr : 뮤텍스 속성, 객체의 주소, NULL (우리는 NULL)

// 뮤텍스 잠금, 잠금해제 함수, 성공하면 0 리턴
int pthread_mutex_lock(pthread_mutex_t *mutex); //사용중
int pthread_mutex_unlock(pthread_mutex_t *mutex); //사용 가능 상태
// mutex : 뮤텍스 객체

//뮤텍스 해제 함수, 성공하면 0 리턴
int pthread_mutex_destroy(pthread_mutex_t *mutex);
// mutex : 뮤텍스 객체</code></pre>
<p>그래서 어떻게 쓰냐고요?
우선 먼저 뮤텍스를 생성해주자. 귀찮으니 포크 뮤텍스 할당하는것만 올린다</p>
<pre><code class="language-c">arg-&gt;fork = malloc(sizeof(pthread_mutex_t) * arg-&gt;philo_num);
    if (!arg-&gt;fork)
        return (1);
    while (i &lt; arg-&gt;philo_num)
    {
        if (pthread_mutex_init(&amp;(arg-&gt;fork[i]), NULL) == -1)
            return (1);
        i++;
    }
</code></pre>
<p>이 뮤텍스를 어디에 쓰느냐? <code>동시에</code> 접근 할 것 같은 변수 앞뒤로 써주면 된다. 한번에 한 쓰레드만 변수에 접근 권한을 주어 데드락을 막는것이다.</p>
<h3 id="3-쓰레드">3. 쓰레드</h3>
<p>사용하는 함수 </p>
<pre><code class="language-c">#include &lt;pthread.h&gt;

// 쓰레드 생성 함수
int  pthread_create(pthread_t  *  thread, pthread_attr_t *attr, void * (*start_routine)(void *), void * arg);
// thread : thread ID (thread의 주소)
// attr : thread의 속성을 저장하는 구조체 (NULL로 셋팅)
// start_routine : thread와 함께 호출되는 함수 포인터 (thread가 실행하는 함수)
// arg : start_routine에 전달되는 매개변수 (없으면 NULL)

// 쓰레드의 종료를 기다리는 함수, 성공시 0 리턴
int pthread_join(pthread_t th, void **thread_return);
// thread : thread ID
// retval : thread가 종료하면서 반환하는 값에 접근할 수 있는 더블 포인터</code></pre>
<p>main process는 thread의 종료를 기다려주지않고 종료되기때문에, 메인 프로세스에서 thread의 종료를 pthread_join를 이용하여 기다려 줄 것이다.</p>
<pre><code class="language-c">while (i &lt; arg-&gt;philo_num)
    {
        pthread_mutex_lock(&amp;philo-&gt;arg-&gt;mutex_last_eat);
        philo[i].last_eat = get_time();
        pthread_mutex_unlock(&amp;philo-&gt;arg-&gt;mutex_last_eat);
        philo[i].last_time = get_time();
        if (pthread_create(&amp;(philo[i].thread), NULL, thread_f, &amp;philo[i]))
            return (1);
        i++;
    }</code></pre>
<p>나는 이런식으로 쓰레드를 생성할 수 있게 해주었다.
지금보니 참 거지같은 코드다. 실제로 200명 이상 돌리면 시작시간이 밀리는 경우가 발생한다. 뮤텍스 하나를 더 사용하여 동시에 시작할 수 있도록 해줄 걸 그랬다. </p>
<h3 id="4-먹고-자고-생각하는-철학자들">4. 먹고 자고 생각하는 철학자들</h3>
<p>진짜 개그지같은 코드지만. 철학자 쓰레드의 함수다.</p>
<pre><code class="language-c">void    *thread_f(void *data)
{
    t_philo        *philo;

    philo = data;
    if (philo-&gt;id % 2 == 0)
        usleep(100);
    while (!checking(philo-&gt;arg)) // 죽었는지 살았는지 체크
    {
        if (get_fork(philo)) //포크 잡다 죽었으면 종료
            break ;
        if (checking(philo-&gt;arg))
        {
            pthread_mutex_unlock(&amp;(philo-&gt;arg-&gt;fork[philo-&gt;left]));
            pthread_mutex_unlock(&amp;(philo-&gt;arg-&gt;fork[philo-&gt;right]));
            break ;
        }
        philo_eating(philo); // 식사
        if (checking(philo-&gt;arg)) // 다 먹었는데 누구 죽었음 종료
            break ;
        philo_printf(philo, philo-&gt;id, &quot;is sleeping&quot;);
        ft_usleep(philo-&gt;arg-&gt;sleep_time);
        if (checking(philo-&gt;arg)) // 자고 일났는데 누구 죽었음 종료
            break ;
        philo_printf(philo, philo-&gt;id, &quot;is thinking&quot;);
    }
    return (0);
}</code></pre>
<p>과하다. 근데 데이터 레이스를 잡다보니 이렇게 되었다 머 어쩌겠어요
아래는 포크 잡는 함수. 1명일때 예외처리 해놓은 부분때문에 작성함</p>
<pre><code class="language-c">int    get_fork(t_philo *philo)
{
    if (philo-&gt;arg-&gt;philo_num == 1) //한명일 때 예외처리
    {
        pthread_mutex_lock(&amp;(philo-&gt;arg-&gt;fork[philo-&gt;left]));
        philo_printf(philo, philo-&gt;id, &quot;has taken a fork&quot;);
        pthread_mutex_unlock(&amp;(philo-&gt;arg-&gt;fork[philo-&gt;left]));
        return (1);
    }
    pthread_mutex_lock(&amp;(philo-&gt;arg-&gt;fork[philo-&gt;left]));
    philo_printf(philo, philo-&gt;id, &quot;has taken a fork&quot;);
    pthread_mutex_lock(&amp;(philo-&gt;arg-&gt;fork[philo-&gt;right]));
    philo_printf(philo, philo-&gt;id, &quot;has taken a fork&quot;);
    return (0);
}</code></pre>
<p>오잉 잠깐. 여기서 philo_eating함수 보기전에 우리는 데이터 레이스에 대해 알아야해요</p>
<h3 id="5-데이터-레이스">5. 데이터 레이스</h3>
<p>여러 쓰레드/프로세스가 공유자원에 동시에 접근하려 할 때 일어납니다. 우리 같은 경우, 두 철학자가 동시에 포크에 접근하는 경우나, 모니터링 함수와 철학자 쓰레드에서 동시에 last_eat 변수에 접근하는 경우를 예시로 들 수 있어요.</p>
<blockquote>
<p>어떻게 막아용 ??</p>
</blockquote>
<p>어떡하긴여 뮤텍스로 잘 막아줘야조 ^^
이팅 함수로 예시를 들어보겠습니다</p>
<pre><code class="language-c">void    philo_eating(t_philo *philo)
{
    philo_printf(philo, philo-&gt;id, &quot;is eating&quot;);
    pthread_mutex_lock(&amp;philo-&gt;arg-&gt;mutex_last_eat);
    philo-&gt;last_eat = get_time();
    pthread_mutex_unlock(&amp;philo-&gt;arg-&gt;mutex_last_eat);
    ft_usleep(philo-&gt;arg-&gt;eat_time);
    pthread_mutex_lock(&amp;philo-&gt;arg-&gt;mutex_eat_cnt);
    philo-&gt;eat_count++;
    pthread_mutex_unlock(&amp;philo-&gt;arg-&gt;mutex_eat_cnt);
    pthread_mutex_unlock(&amp;(philo-&gt;arg-&gt;fork[philo-&gt;left]));
    pthread_mutex_unlock(&amp;(philo-&gt;arg-&gt;fork[philo-&gt;right]));
}</code></pre>
<p>여기서 어떤 부분이냐</p>
<pre><code class="language-c">pthread_mutex_lock(&amp;philo-&gt;arg-&gt;mutex_last_eat);
philo-&gt;last_eat = get_time();
pthread_mutex_unlock(&amp;philo-&gt;arg-&gt;mutex_last_eat);</code></pre>
<p>last_eat에 write하기전에, 앞 뒤를 뮤텍스로 막아준 것이 보이는가? 왜냐하면 나는 이 last_eat변수를 모니터링 함수에서 철학자가 죽었는지 확인 할 때 사용한다. 동시에 접근하는 상황을 막기위해 만들어 주었다.</p>
<blockquote>
<p>최근에 필로 평가가면 데이터레이스 검사를 안 해보셨거나 잘못 검사하신 분들이 많다. cflag에 <code>-g -fsanitize=thread</code> 옵션을 추가하여 함께 컴파일 해보길 바란다. 
왜냐면 딱 봐도 데이터 레이스 날 것 같은데 어 안났는데용? 사람들이 있따 ^^,,, 제대로 컴파일 안 했으먼서!! 아무튼 꼭 해라
그리고 데이터 레이스가 어디서 발생했는지 상세히 알려주니 에러를 읽어보면 쉽게 고칠 수 있다.</p>
</blockquote>
<h3 id="6-시간">6. 시간</h3>
<p>우리가 사용할 구조체</p>
<pre><code class="language-c"># include &lt;sys/time.h&gt;

struct timeval
{
    long tv_sec;       // 초
    long tv_usec;      // 마이크로초
}</code></pre>
<p>나는 모든 시간을 long 으로 바꾸어 가지게 해주었다. 종종 timeval구조체를 들고다니시기도 하더라. 머 똑같다.</p>
<pre><code class="language-c">long    get_time(void)
{
    struct timeval    time;
    long            result;

    gettimeofday(&amp;time, NULL);
    result = ((size_t)time.tv_sec * 1000) + ((size_t)time.tv_usec / 1000);
    return (result);
}</code></pre>
<p>중요한 부분이다. 나는 ft_usleep 함수를 만들어 usleep()을 100usec씩 나누어서 해주었다 왜일까요 ?</p>
<pre><code class="language-c">void    ft_usleep(long sleep_time)
{
    long    start;

    start = get_time();
    while (start + (sleep_time * 1) &gt; get_time())
        usleep(100);
}</code></pre>
<p>시작 전 컨텍스트 스위칭에 대해 언급하였다. 그 사유니까 다시 올라가서 읽으면 된다. 이 부분은 현진님께서 가르쳐주셨당 최고의 개발자~</p>
<h3 id="7-모니터링-함수">7. 모니터링 함수</h3>
<p>다 왔다 진짜 마지막!! 메인 함수에서 죽은 철학자들이 없는지 검사해주는 함수이다. 모니터링 함수는 (<a href="https://techdebt.tistory.com/32">https://techdebt.tistory.com/32</a>) 블로그를 참조했다. 그치만 저는 데이터레이스를 막기위해 더 더러운 함수가 되었어용</p>
<pre><code class="language-c">void    monitoring(t_philo *philo, t_arg *arg)
{
    int        i;
    long    now_time;

    while (!checking(arg))
    {
        if (arg-&gt;eat_num != 0 &amp;&amp; check_eat_cnt(philo, arg) == arg-&gt;eat_num)
        {
            change_monitor(arg);
            break ;
        }
        i = 0;
        while (i &lt; arg-&gt;philo_num)
        {
            now_time = get_time();
            if ((now_time - last_eat(&amp;philo[i])) &gt; arg-&gt;life_time)
            {
                philo_printf(&amp;philo[i], philo[i].id, &quot;died&quot;);
                change_monitor(arg);
                break ;
            }
            i++;
        }
        usleep(10);
    }
}</code></pre>
<p>여기서 checking(arg)함수만 잠깐 살펴보면,,</p>
<pre><code class="language-c">int    checking(t_arg *arg)
{
    pthread_mutex_lock(&amp;arg-&gt;mutex_monitor);
    if (arg-&gt;monitor == 1)
    {
        pthread_mutex_unlock(&amp;arg-&gt;mutex_monitor);
        return (1);
    }
    else
    {
        pthread_mutex_unlock(&amp;arg-&gt;mutex_monitor);
        return (0);
    }
}</code></pre>
<p>머 데이터 레이스를 막으려고 모두 함수화 한 부분이다. 내 모든 뮤텍스들은 이렇게 일 하고있다. 개인의 코드마다 데이터 레이스 나는 부분은 다르니, 컴파일 해보시며 뮤텍스를 적절히 넣기를 바랍니다.</p>
<p>멘데토리는 이게 끝이다. 그치만 여기에 지치지마시고 보너스도 하셨음 좋겠다. 왜냐면 ㄹㅇ 학교에서 배운다. 보너스도 읽어줘라 왜냐면 내 보너스 뿌듯함 ㅇㅇ</p>
<h1 id="bonus">Bonus</h1>
<p>보너스 진짜 생각보다 안 어려움
그런데 멘데로티에서 가져올 코드는 거의 없습니다. 새로운 세미 과제를 하나 더 클리어 한다는 느낌으로 시작해야함 ^^ 하하하 가지마세요 ㅜ</p>
<h4 id="시작하기전에-잠시만여">시작하기전에 잠시만여</h4>
<blockquote>
<p>멘데토리에서는 철학자를 thread로 만들어주고 mutex를 이용하여 데드락을 막았다. 보너스에서는 철학자가 각각의 process여야하고, semaphore를 이용하여 데드락을 막아 줄 것이다.</p>
</blockquote>
<h3 id="0-구조-1">0. 구조</h3>
<pre><code class="language-c">typedef struct s_philo
{
    int                philo_num;
    int                life_time;
    int                eat_time;
    int                sleep_time;
    int                eat_num;
    /* sem_t        세마포어들 생략 */
    int                id;
    int                eat_count;
    long            start_time;
    pthread_t        thread;
    struct timeval    time;
}    t_philo;</code></pre>
<p>이 구조체 하나면 됨. 와~ </p>
<h3 id="1-파싱-1">1. 파싱</h3>
<pre><code class="language-c">int    init_argv(t_philo *philo, int argc, char **argv)</code></pre>
<p>위에서 쓴 init 함수만 그대로 가져다 쓸 수 있다. 나머진 다 다르다. 울지마세용 ㅜㅜ</p>
<h3 id="2-세마포어">2. 세마포어</h3>
<p>제가 선언한 세마포어들입니다. 얘는 다 세마포어 포인터입니다. 개수가 몇개든</p>
<pre><code class="language-c">sem_t            *fork;
sem_t            *print;
sem_t            *die;</code></pre>
<p>아래로 세마포어 함수</p>
<pre><code class="language-c"># include &lt;semaphore.h&gt;

// 세마포어 생성 함수
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
// name : 세마포어 이름
// oflag : 세마포어 특징 (O_RDWR, O_RDONLY, O_CREAT, O_EXCL)
// mode : 권한 정보 (chmod 777 그거)
// value : 세마포어 초기값 (ex. 포크가 5개 필요하면 5)

// 세마포어에 접근하고, 반납하는 함수, 성공하면 0 리턴
int sem_wait(sem_t *sem); // 접근 제한
int sem_post(sem_t *sem); // 반납
// sem : 세마포어 포인터

int sem_unlink(const char *name); // 세마포어 제거
int sem_close(sem_t *sem);v // 세마포어 종류</code></pre>
<p>헷갈리면 코드를 보며 이해해보자.</p>
<pre><code class="language-c">void    init_sem(t_philo *philo)
{
    sem_unlink(&quot;sem_fork&quot;); // 겹치는 이름이 있을수 있으니 삭제
    sem_unlink(&quot;sem_print&quot;);
    sem_unlink(&quot;sem_die&quot;);
    philo-&gt;fork = sem_open(&quot;sem_fork&quot;, O_CREAT, 0644, philo-&gt;philo_num);
    philo-&gt;print = sem_open(&quot;sem_print&quot;, O_CREAT, 0644, 1);
    philo-&gt;die = sem_open(&quot;sem_die&quot;, O_CREAT, 0644, 1);
}</code></pre>
<p>open의 인자를 한번 더 설명하자면, &quot;sem_fork&quot; 이름, O_CREAT 옵션, 접근권한 0644, philo-&gt;philo_num 개수만큼 변수값 설정.
O_CREAT옵션은 해당 이름의 객체가 존재하지 않을 경우, 새로운 객체를 생성하는 옵션이다.
포크는 철학자 수 만큼 필요하니 philo_num으로 설정해주었다.</p>
<p>이제 이 세마포어를 어떻게 쓰는지 알아보자.</p>
<pre><code class="language-c">int    get_fork(t_philo *philo)
{
    if (philo-&gt;philo_num == 1)
    {
        sem_wait(philo-&gt;fork);
        philo_printf(philo, philo-&gt;id, &quot;has taken a fork&quot;);
        sem_wait(philo-&gt;fork);
        return (1);
    }
    sem_wait(philo-&gt;fork);
    philo_printf(philo, philo-&gt;id, &quot;has taken a fork&quot;);
    sem_wait(philo-&gt;fork);
    philo_printf(philo, philo-&gt;id, &quot;has taken a fork&quot;);
    return (0);
}</code></pre>
<p>보면 알겠지만 멘데토리의 포크 함수와 똑같다. 다만 pthread_mutex_lock -&gt; sem_wait 의 차이</p>
<p>사실뮤텍스와 세마포어의 가장 큰 차이는 repeat부분에서 나온다. 그 전에, fork()에 대해 알아보자.</p>
<h3 id="3fork">3.fork()</h3>
<p>이거 철학자들이 집는 포크 아니다. 자식 프로세스를 생성하는 함수에용</p>
<pre><code class="language-c">#include &lt;unistd.h&gt;

pid_t fork(void);
// 부모 프로세스의 리턴값 : 자식 프로세스의 pid
// 자식 프로세스의 리턴값 : 0</code></pre>
<p>minishell 해결한사람에게는 껌이겠고, 아닌 사람은 미칠 것이다. 본인은 미니셸을 해결한 후 필로 보너스를 했기에 ^^ 
간단히 설명하자면, 철학자 수 만큼 자식 프로세스를 생성 할 것이다.</p>
<p>자식 프로세스는 fork되는 순간, 부모 프로세스의 <code>모든 정보를 복사</code>한 <code>독립적인 메모리 영역</code>이 생성된다. 이후 각각의 프로세스는 독립적으로 실행된다.</p>
<pre><code class="language-c">int    make_child(t_philo *philo)
{
    pid_t    *pid;
    int        i;

    i = -1;
    pid = (pid_t *)malloc(philo-&gt;philo_num * sizeof(pid_t));
    if (!pid)
        return (1);
    philo-&gt;start_time = get_time();
    while (++i &lt; philo-&gt;philo_num)
    {
        pid[i] = fork(); // 자식 프로세스 생성
        if (pid[i] &lt; 0) // 에러 처리
            return (1);
        if (pid[i] == 0) // 자식이면
        {
            philo-&gt;id = i; //철학자 넘버 지정
            break ;
        }
    }
    if (pid[philo-&gt;id] == 0 &amp;&amp; !child(philo)) //자식이면 자식 함수 실, norm맞춘다구 이모양!
        return (1);
    else
        parents(philo, pid); //부모 함수 실행
    free(pid);
    return (0);
}</code></pre>
<p>대충 감이오나여? </p>
<p>이제 부모 프로세스가 실행하는 함수와 자식 프로세스가 실행하는 함수의 구현부를 볼 것.</p>
<pre><code class="language-c">int    child(t_philo *philo)
{
    philo-&gt;id += 1; // 0부터 시작해서 +1
    philo-&gt;eat_count = 0; //횟수 초기화
    gettimeofday(&amp;philo-&gt;time, NULL); 
    if (pthread_create(&amp;(philo-&gt;thread), NULL, monitoring, philo)) // 모니터링 쓰레드 생성
        return (1);
    repeat(philo); // 먹고 자고 생각하고 반복하는 함수
    exit(0);
    return (0);
}</code></pre>
<p>이거 좀 정신 나갈 것 같죠
여기서 부터 다른점!!!!!!!!
이렇게 생성된 자식 프로세스 = 한명의 철학자
이 모든 철학자 프로세스의 함수에서 반복적인 활동을 함
그럼 이 철학자들이 죽었는지 체크하는 역할은 누가하냐? 쓰레드가 함.</p>
<h4 id="정리--자식-프로세스-하나--철학자-한명-철학자-한명-당-모니터링-쓰레드-하나">정리 : 자식 프로세스 하나 = 철학자 한명, 철학자 한명 당 모니터링 쓰레드 하나</h4>
<p>철학자가 200명이면 메인프로세스 포함 201개, 쓰레드 200개가 생성됨 ㅋㅋㅋ 느려요 진짜 느림. 그치만 200명 안 죽고 돌아갑니다 우하하!!</p>
<p>그럼 철학자 한명이라도 죽으면 어떻게 동작하느냐? 이제 볼거임</p>
<pre><code class="language-c">void    parents(t_philo *philo, pid_t *pid)
{
    int    status;
    int    i;

    i = 0;
    while (i &lt; philo-&gt;philo_num)
    {
        waitpid(-1, &amp;status, 0); // 자식 프로세스 기다림
        if (status != 0) // 오류나면
        {
            i = 0;
            while (i &lt; philo-&gt;philo_num)
            {
                kill(pid[i], SIGKILL); // 전부 다주겨
                i++;
            }
        }
        i++;
    }
}</code></pre>
<p>화긴? 중요한 부분은 waitpid(-1, &amp;status, 0); 입니다.
임의의 자식의 종료를 기다림. 정상 종료된 철학자들의 수 (i)가 철학자 수 만큼 될 때까지 기다림. </p>
<p>그럼 오류는 언제 나느냐? 철학자가 한명이라도 죽었을때. 오잉 그건 어떻게 아나요? 모니터링 쓰레드에서 알아보아요</p>
<h3 id="4-repeat-함수">4. repeat 함수</h3>
<p>모든 철학자 프로세스가 실행하는 함수.</p>
<pre><code class="language-c">void    repeat(t_philo *philo)
{
    if (philo-&gt;id % 2 == 0)
        usleep(200);
    while (1)
    {
        if (get_fork(philo))
            break ;
        philo_eating(philo);
        if (philo-&gt;eat_num != 0 &amp;&amp; philo-&gt;eat_count == philo-&gt;eat_num)
            exit (0);
        philo_printf(philo, philo-&gt;id, &quot;is sleeping&quot;);
        ft_usleep(philo-&gt;sleep_time);
        philo_printf(philo, philo-&gt;id, &quot;is thinking&quot;);
    }
}</code></pre>
<p>멘데토리보다 훨씬 간단하다. 저기보면 exit(0)보이시나요? 밥 다 먹었으면 정상종료 (0) 하겠다는 뜻입니다. 그럼 비정상종료는 어떻게 하느냐?</p>
<h3 id="5-모니터링-쓰레드">5. 모니터링 쓰레드</h3>
<p>훨씬 함수가 간단하고 많이 줄었다. 따로 더 구현할 함수도 없다.</p>
<pre><code class="language-c">void    *monitoring(void *data)
{
    t_philo        *philo;
    long        now_time;
    long        last_time;

    philo = data;
    while (1)
    {
        now_time = get_time();
        sem_wait(philo-&gt;die);
        last_time = ((size_t)philo-&gt;time.tv_sec * 1000) + \
        ((size_t)philo-&gt;time.tv_usec / 1000);
        if (now_time - last_time &gt; philo-&gt;life_time)
        {
            philo_printf(philo, philo-&gt;id, &quot;died&quot;);
            exit(1);
        }
        sem_post(philo-&gt;die);
        usleep(100);
    }
}</code></pre>
<p><code>exit(1)로 비정상 종료</code>
가 되면, 위에 있는 부모 프로세스에서 <code>kill</code>을 이용하여 모든 자식 프로세스를 강제종료한다. 와~ 끗. 간단하죠 ?</p>
<p>진심 보너스 별거 없음 마음만 먹으면 하루만에 뚝딱!! 가능하다구!! </p>
<p>하 근데 오ㅐ케 기냐
멘데토리는 정리하지 말걸
아무튼 제 점수 보고가세요 안녕</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/58eff875-c51c-4ce9-b397-500fe96e1b85/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] Programmers - PCCP 모의고사 1회 4번 운영체제]]></title>
            <link>https://velog.io/@min_gi1123/c-Programmers-PCCP-%EB%AA%A8%EC%9D%98%EA%B3%A0%EC%82%AC-1%ED%9A%8C-4%EB%B2%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C</link>
            <guid>https://velog.io/@min_gi1123/c-Programmers-PCCP-%EB%AA%A8%EC%9D%98%EA%B3%A0%EC%82%AC-1%ED%9A%8C-4%EB%B2%88-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C</guid>
            <pubDate>Sun, 19 Feb 2023 08:00:15 GMT</pubDate>
            <description><![CDATA[<p>PCCP 모의고사 1회 4번 유전법칙</p>
<p>priority_queue의 compare 구조체를 만들 수 있는 사람에게는 어렵지 않은 문제였을것.
백준 회의실 배정문제와 유사하다고 생각되었음.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/cf305f7f-8046-4d35-97a1-67eb44f91755/image.png" alt=""></p>
<p>본인은 compare 구조체를 하나만 쓰기위해 compare 안에서 전역변수를 참조하도록 코드를 짰는데, 그렇게 하면 오류가 생긴다,, 고 한다.</p>
<p>그래서 로직을 변경해서 우선순위 큐 2개를 씀</p>
<ol>
<li><code>실행순서</code>가 기준인 priority_queue -&gt;pq</li>
<li><code>우선순위</code>가 기준인 priority_queue -&gt;pq2</li>
</ol>
<h3 id="priority_queue-compare-구조체">priority_queue compare 구조체</h3>
<pre><code class="language-cpp">struct CompareVector {
    bool operator()(const vector&lt;long long&gt;&amp; a, const vector&lt;long long&gt;&amp; b){
        if (a[1] == b[1])
            return a[0] &gt; b[0];
        else
            return a[1] &gt; b[1];
    }
};

struct CompareVector2{
    bool operator()(const vector&lt;long long&gt;&amp; a, const vector&lt;long long&gt;&amp; b){
        if (a[0] == b[0])
            return a[1] &gt; b[1];
        else
            return a[0] &gt; b[0];
    }
};</code></pre>
<h3 id="반복">반복</h3>
<ol>
<li><code>pq</code> 에서 현재 시간을 기준으로 실행할 수 있는 프로그램을 꺼내서 <code>pq2</code>    에 push</li>
<li><code>pq2</code> 에 원소가 있다면 top을 꺼내서 갱신
2-1. 이때 현재시간보다 실행시간이 빠르다면 지연 시간 갱신</li>
<li><code>pq2</code> 가 비어있다면 현재시간에 실행시킬 수 있는 프로그램이 없는 것. <code>pq</code>의 top을 꺼내서 현재시간 갱신</li>
<li>종료후 현재 시간을 answer에 갱신! 끗!</li>
</ol>
<h3 id="code">code</h3>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;queue&gt;

using namespace std;

struct CompareVector {
    bool operator()(const vector&lt;long long&gt;&amp; a, const vector&lt;long long&gt;&amp; b){
        if (a[1] == b[1])
            return a[0] &gt; b[0];
        else
            return a[1] &gt; b[1];
    }
};

struct CompareVector2{
    bool operator()(const vector&lt;long long&gt;&amp; a, const vector&lt;long long&gt;&amp; b){
        if (a[0] == b[0])
            return a[1] &gt; b[1];
        else
            return a[0] &gt; b[0];
    }
};

priority_queue&lt;vector&lt;long long&gt;, vector&lt;vector&lt;long long&gt;&gt;, CompareVector&gt; pq;
priority_queue&lt;vector&lt;long long&gt;, vector&lt;vector&lt;long long&gt;&gt;, CompareVector2&gt; pq2;

vector&lt;long long&gt; solution(vector&lt;vector&lt;int&gt;&gt; program) {
    vector&lt;long long&gt; answer;

    for(int i=0; i&lt;11; i++)
        answer.push_back(0);

    for (int i=0; i&lt;program.size(); i++)
    {
        vector&lt;long long&gt; temp;
        temp.push_back(program[i][0]);
        temp.push_back(program[i][1]);
        temp.push_back(program[i][2]);
        pq.push(temp);

        temp = pq.top();
    }

    long long nowtime = 0;

    while (!pq.empty() || !pq2.empty())
    {
        vector &lt;long long&gt; v;

        while (!pq.empty())
        {
            v = pq.top();
            if (v[1] &gt; nowtime)
                break;
            pq2.push(v);
            pq.pop();
        }

        if (pq2.empty())
        {
            v = pq.top();
            nowtime = v[1] + v[2];
            pq.pop();
        }
        else
        {
            v = pq2.top();
            if (nowtime &gt; v[1])
            {
                answer[v[0]] += (nowtime - v[1]);
                nowtime += v[2];
            }
            else
                nowtime += v[2];
            pq2.pop();
        }
    }

    answer[0] = nowtime;

    return answer;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/fe5686d3-609f-4bac-9d21-b4c7fff0d48c/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[구조패턴 - 어댑터 패턴 (쉽게 배워 바로 써먹는 디자인 패턴)]]></title>
            <link>https://velog.io/@min_gi1123/%EA%B5%AC%EC%A1%B0%ED%8C%A8%ED%84%B4-%EC%89%BD%EA%B2%8C-%EB%B0%B0%EC%9B%8C-%EB%B0%94%EB%A1%9C-%EC%8D%A8%EB%A8%B9%EB%8A%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@min_gi1123/%EA%B5%AC%EC%A1%B0%ED%8C%A8%ED%84%B4-%EC%89%BD%EA%B2%8C-%EB%B0%B0%EC%9B%8C-%EB%B0%94%EB%A1%9C-%EC%8D%A8%EB%A8%B9%EB%8A%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Fri, 18 Nov 2022 20:18:50 GMT</pubDate>
            <description><![CDATA[<h2 id="⚙️-어댑터-패턴">⚙️ 어댑터 패턴</h2>
<p>어댑터 패턴은 코드를 재사용하기위해 구조를 변경하는 패턴입니다.
(구조 패턴중 가장 간단합니다 ^__^)</p>
<hr>
<h2 id="어댑터">어댑터</h2>
<p>어댑터 패턴은 다른 말로 래퍼 패턴(wrapper pattern)이라고 합니다. 래퍼는 감싸다는 의미로, <code>기존의 클래스를 새로운 클래스로 감싸는 기법</code> 입니다. 래퍼 처리로 기존의 기능은 유지하면서 변경된 추가 코드를 삽입합니다. </p>
<p>래퍼 처리된 객체를 어댑터라고 합니다.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/e3b90de2-85a4-4552-913f-ea84cbe2648f/image.jpeg" alt=""></p>
<p>직접 사진찍은건데 좀 짜그라졌네요.</p>
<ul>
<li>어댑터 : 변환을 처리하는 객체</li>
<li>어댑티 : 변환을 받아 사용하는 객체</li>
</ul>
<hr>
<h2 id="어댑터-종류">어댑터 종류</h2>
<p>어댑터는 다른 객체의 구조를 내가 원하는 인터페이스 방식으로 개선합니다. 구조를 개선하는 방법은 클래스의 상속을 이용하는 방법과 구성을 이용하는 방법 2가지 입니다.</p>
<ul>
<li>클래스 어댑터 : 상속</li>
<li>객체 어댑터 : 구성</li>
</ul>
<h3 id="클래스-어댑터">클래스 어댑터</h3>
<p>클래스 어댑터는 클래스의 상속 특성을 이용하며, 클래스 어댑터를 사용하기 위해서는 다중 상속이 필요합니다.</p>
<p>다중 상속이란 하나의 클래스가 2개 이상의 클래스에서 상속되는것을 말 합니다. 클래스 어댑터는 2개의 클래스를 받아 기존 클래스의 메서드를 다른 메서드로 대체하는 방법입니다.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/7831b40e-3f4e-4bc2-a1a4-f2df4177e29c/image.jpeg" alt=""></p>
<p>근데.. 그거 아십니까 최신 프로그래밍 언어는 다중 상속을 지원하지 않습니다. php와 java또한 단일상속만 지원합니다. 다중 상속에서는 클래스 메서드의 충돌이 발생합니다.</p>
<p>아무래도 최신 언어로 다중상속을 이용하여 클래스 어댑터를 표현하기는 어렵겠습니다.</p>
<p>그러나 클래스 어댑터는 별도의 어댑티를 만들지 않으며, 하나의 클래스로 어댑티 객체를 처리할 수 있다는 장접이 있습니다.</p>
<h3 id="객체-어댑터">객체 어댑터</h3>
<p>객체 어댑터는 객체의 의존성을 이용해 문제를 해결합니다. 객체 어댑터는 기존 타깃인 객체의 인터페이스에 영향을 받으며, 타깃의 인터페이스가 복잡할수록 많은 작업이 필요합니다.</p>
<p>객체 어댑터는 내부적으로 객체를 재구성합니다. 구성을 위해 기존 객체는 복합 객체로 변환됩니다.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/e8f9b528-3b23-4b66-828e-4fd89c42e38c/image.jpeg" alt=""></p>
<p>어댑터는 인터페이스를 변경합니다. 하지만 어댑터는 인터페이스로 <strong>캡술화</strong> 됐기 때문에 클라이언트에서 변화를 눈치채지 못한채 그대로 사용할 수 있습니다. 어댑터 패턴은 객체의 호환성을 개선하기 위한 기능들로 새롭게 합성합니다.</p>
<p>객체를 구성으로 결합하면 느슨한 연결 방식으로, 보다 많은 유연성을 확보할 수 있다는 장점이 있습니다. 그리고 구성은 프로그램 실행 도중에도 객체를 변경할 수 있습니다.</p>
<hr>
<h2 id="예제">예제</h2>
<h3 id="⛏️-기존-코드">⛏️ 기존 코드</h3>
<pre><code class="language-php">&lt;php 
//원본소스 
class Math
{
    //입력한 값이 2배 증가합니다.
    // 입력값과 반환값은 float형입니다.
    public function twoTime (float $num): float
    {
        echo &quot;실수 2배 적용합니다. In&quot;
        return $num*2;
    }
    //입력한 값이 절반으로 감소합니다.
    // 입력값과 반환값은 float형입니다.
    public function halfTime(float $num): float
    {
    echo &quot;실수 1/2배 적용합니다. In&quot;;
    return $num/2;
    }
}</code></pre>
<p>곱셈을 계산하는 메서드 입니다. 매개변수 인자로 실수값을 받습니다.</p>
<p>만약 인자값이 정수로 변경된다고 가정하면, 더이상 이 Math 클래스를 사용할 수 없습니다. 우리는 어댑터 패턴으로 이 문제를 해결할거에요.</p>
<h3 id="⛏️-어댑터-제작">⛏️ 어댑터 제작</h3>
<pre><code class="language-php">&lt;?php
// 어댑터 인터페이스
interface Adapter
{
    public function twice0f(int $num):int; 
    public function half0f(int $num):int;
}</code></pre>
<p>인터페이스에서 입력한 값을 보정합니다. 정수 타입으로 지정한 후, 알맞는 구체 클래스를 만듭니다.
+) 인터페이스 변경을 담당하는 클래스를 플러그블 어댑터라고 합니다.</p>
<h3 id="⛏️-구현-코드">⛏️ 구현 코드</h3>
<pre><code class="language-php">&lt;?php
//새롭게 구현된 코드
class Objects implements Adapter
{
    private $_adapter;

    function _construct()
    {
    //기존 클래스의 객체를 생성합니다.
    $this-&gt;_adapter = new math;
    }

    public function twice0f (int $num):int
    {
        echo &quot;정수 2배 적용합니다. n&quot;;
        //캐스팅을 통해 실수로 변환하여 전달합니다.
        $_num = $this-&gt;_adapter-&gt;twoTime( (float)$num );
        //캐스팅을 통해 정수로 변환하여 반환합니다.
        return (int)$_num;
    }

    public function half0f(int $num): int
    {
        echo &quot;정수 1/2배 적용합니다. \n&quot;;

        //캐스팅을 통해 실수로 변환하여 전달합니다.
        $num = $this-&gt;_adapter-&gt;halfTime( (float)$num );
        //캐스팅을 통해 정수로 변환하여 반환합니다.
        return (int)$_num;
    }
}</code></pre>
<p>작성한 어댑터는 기존의 Math 클래스를 상속받지 않습니다. 그 대신 객체의 생성자에서 기존 Math 클래스의 객체를 생성합니다. 어댑터는 생성자에서 새로운 객체를 생성, 포함함으로 <strong>복합객체</strong> 입니다.</p>
<p>입력된 정숫값을 실숫값으로 캐스팅하고, 기존 Math클래스의 메서드를 호출합니다. 결과값도 캐스팅해서 정수값으로 변경한 후 반환됩니다.</p>
<h3 id="⛏️-클라이언트-코드">⛏️ 클라이언트 코드</h3>
<pre><code class="language-php">‹?php 
include &quot;Math.php&quot;;
include &quot;Adapter.php&quot;;
include &quot;Object.php&quot;;

sobi = new Objects;

//어댑터를 이용하여 두 배 계산합니다.
echo $obj-&gt;twice0f(5);
echo &quot;\n&quot;;

//어댑터를 이용하여 절반을 계산합니다.
echo $obj-›half0f(4);</code></pre>
<p>이제 실행해볼까요.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/dab554a1-8bcf-4ee9-9efb-54274c9a0518/image.jpeg" alt=""></p>
<p>일단 지금은 책에 있는 예제인데 자고 일어나서 테스트해보고 제가 한 예제로 바꿀게요 &gt;&lt;</p>
<p>이처럼 어댑터 패턴을 이용하면 클래스와 메서드를 수정하지 않고, 원하는 형태로 변경 할 수 있습니다.</p>
<pre><code>어댑터 패턴은 한국에서 사용되는 220V 가전제품을 
일본에서 110V에 연결하기 위해 
변환 어댑터와 같은 컨버터를 사용하는 것으로 비유할 수 있습니다.</code></pre><hr>
<p>실습하실 분들을 위해,, 예제 코드를 올려드립니다. 제가 다 쳤습니다.
사실 아니고 아이폰 짱짱맨이 텍스트 읽어줘서 수정 조금만 했습니다.
증말 최고.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[구조패턴이란 + 종류 (쉽게 배워 바로 써먹는 디자인 패턴)]]></title>
            <link>https://velog.io/@min_gi1123/%EA%B5%AC%EC%A1%B0%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80-%EC%A2%85%EB%A5%98-%EC%89%BD%EA%B2%8C-%EB%B0%B0%EC%9B%8C-%EB%B0%94%EB%A1%9C-%EC%8D%A8%EB%A8%B9%EB%8A%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@min_gi1123/%EA%B5%AC%EC%A1%B0%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80-%EC%A2%85%EB%A5%98-%EC%89%BD%EA%B2%8C-%EB%B0%B0%EC%9B%8C-%EB%B0%94%EB%A1%9C-%EC%8D%A8%EB%A8%B9%EB%8A%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Fri, 18 Nov 2022 20:02:50 GMT</pubDate>
            <description><![CDATA[<h2 id="🛠️-구조패턴">🛠️ 구조패턴</h2>
<p><code>구조패턴</code>은 객체와 클래스를 <code>확장</code>시키는 방법입니다.</p>
<h3 id="확장">확장</h3>
<p><code>클래스</code>는 하나의 책임. 역할로 설계됩니다. 하지만 하나의 책임으로는 전체의 기능을 구현 할 수 없습니다.</p>
<p>단일 책임의 원칙은 클래스의 행동을 분리하는 설계원칙입니다. 여러개로 분리된 책임과 행동은 서로 관계를 맺고 주어진 문제를 해결합니다.</p>
<p>객체지향 개발은 클래스를 결합하여 더 큰 객체로 <code>확장</code> 합니다.구조패턴은 큰 구조의 객체를 형성하고관리하는 방법에 대해 설명합니다. 객체를 확장하기위해 클래스의 <code>상속</code>과 <code>합성</code>을 사용합니다.</p>
<h3 id="상속">상속</h3>
<p><code>상속</code>은 객체지향 초창기시절부터 나온 개념입니다. 초기에는 객체를 확장하기위해 상속을 이용했습니다. </p>
<p>상속은 객체지향 고유의 특징입니다. 상속은 <code>정적</code>인 결합을 통해 객체를 확장합니다. 하지만 정적인 상속 결합은 대형 프로그램개발의 유연한 작업엔 한계가 있습니다.</p>
<h3 id="합성">합성</h3>
<p>상속 결합의 단점을 보완하기 위한 기법으로 <code>객체 합성</code>을 사용합니다. <code>합성</code>이란, 하나의 객체가 다른객체에 포함하는 것을 말합니다.</p>
<p>합성은 객체의 강한 의존 관계를 줄이고 유연한 객체 구조로 변결할 수 있으며, 실행 중에도 객체를 확장 할 수 있습니다.</p>
<p>합성을 이용한 객체 확장은, 자원을 보다 효율적으로 사용할 수 있게 합니다.</p>
<p>구조패턴은 상속보다 합성을 통해 다양한 객체 확장 방법을 제안합니다.</p>
<hr>
<h2 id="🔧-구조패턴의-종류">🔧 구조패턴의 종류</h2>
<ul>
<li>어댑터 패턴
인터페이스를 추상화하여 서로 다른 인터페이스를 통일화합니다. 상속을 통한 어댑터와 합성을 통한 어댑터로 구분합니다.</li>
</ul>
<ul>
<li><p>브리지 패턴
  개념과 추상을 구분하여 처리합니다. 또한 객테의 독립으로 확장과 변형이 가능합니다.</p>
</li>
<li><p>복합체 패턴
  객체의 구조를 이용하여 객체를 확장합니다. 복합 객체는 트리 구조의 특징을 갖고 있습니다.</p>
</li>
<li><p>장식자 패턴
  객체의 기능을 동적으로 추가합니다. 확장 시 객체에 새로운 책임을 부과할 수 있습니다. 재귀저거 합성 방법을 응용하여 객체를 확장합니다.</p>
</li>
<li><p>파사드 패턴
  복잡한 객체의 구조와 접근을 간단하게 표현하는 방법입니다.</p>
</li>
<li><p>플라이웨이트 패턴
  플라이웨이트 패턴은 객체를 공유합니다. 객체 공유를 통해 자원의 효율성과 공유된 객체의 일관성을 보장합니다.</p>
</li>
<li><p>프록시 패턴
  객체의 접근을 제한할 수 있습니다. 객체를 액세스 할 때 추가적인 책임을 부여하는 역할을 수행합니다.</p>
</li>
</ul>
<hr>
<p>길이 너무 길어져 구조 패턴에 대한 내용과 종류까지만으로 글을 끊습니다.
이 중 몇가지 패턴을 뽑아 정리하려합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[디자인패턴이란 (쉽게 배워 바로 써먹는 디자인 패턴)]]></title>
            <link>https://velog.io/@min_gi1123/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80-%EC%89%BD%EA%B2%8C-%EB%B0%B0%EC%9B%8C-%EB%B0%94%EB%A1%9C-%EC%8D%A8%EB%A8%B9%EB%8A%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@min_gi1123/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80-%EC%89%BD%EA%B2%8C-%EB%B0%B0%EC%9B%8C-%EB%B0%94%EB%A1%9C-%EC%8D%A8%EB%A8%B9%EB%8A%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Fri, 18 Nov 2022 18:39:45 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/min_gi1123/post/d87eed90-e2d9-413a-9159-c19a9066182e/image.jpeg" alt=""></p>
<p>&quot;쉽게 배워 바로 써먹는 디자인 패턴&quot;을 읽고~
오늘은 디자인 패턴이 무엇인지 알아볼게요!</p>
<hr>
<h2 id="☹️-디자인책이-아닙니다">☹️ 디자인책이 아닙니다.</h2>
<p>디자인 패턴의 주체는 디자인이 아니라 <code>패턴</code> 이 주체입니다.
어? 그렇다면 <code>디자인패턴</code>과 <code>패턴</code> 은 무엇일까요. </p>
<hr>
<h2 id="♻️-디자인-패턴과-패턴">♻️ 디자인 패턴과 패턴</h2>
<p><code>디자인 패턴</code> 이란 소프트웨어 디자인 과정에서 자주 발생하는 문제들에 대한 전형적인 해결책입니다. </p>
<p><code>패턴</code>은 표준화 된 라이브러리처럼 ctrl x,  ctrl v 가능한게 아니에요. 패턴은 코드 조각이 아니라 <strong>특정 문제를 해결하는 개념</strong> 입니다.</p>
<h4 id="특정-문제를-해결하는-개념은-알고리즘-아닌가요">특정 문제를 해결하는 개념은 알고리즘 아닌가요?</h4>
<p>아니에요. 비슷해보이지만 달라요!!!!!! 간단히 말하자면 알고리즘은 <code>절차</code> 라면, 패턴은 <code>설계 도면</code> 같은거에요. 응용 가능한 도면.</p>
<p><strong>다시 정리하자면 패턴은 재사용성을 가지는 객체지향 소프트웨어의 요소입니다.</strong></p>
<hr>
<h2 id="🛠️-패턴의-분류">🛠️ 패턴의 분류</h2>
<p>패턴은 <code>의도</code>와 <code>목적</code>에 따라 분류가 나뉘어요. </p>
<p>코드의 재사용성과 유연성을 증가시키는 객체 생성 메커니즘을 공유하는 <code>생성 패턴</code></p>
<p>객체와 클래스를 확장시키는 방법인 <code>구조 패턴</code></p>
<p>객체간의 효율적인 행동 처리와 분리를 위한 <code>행동 패턴</code>이 있습니다.</p>
<hr>
<h2 id="⚠️-주의">⚠️ 주의</h2>
<p>패턴을 배웠다고 막 가져다 쓰면 안돼요</p>
<blockquote>
<p>“망치만 있으면 모든 것이 못처럼 보인다.”</p>
</blockquote>
<p>뭔 말이냐면 꼴깝떨지 말라는 말입니다.</p>
<p>패턴에 대해 배웠다고 더 간단한 일에 굳이 패턴을 사용하여 코드를 복잡하게하는 바보같은짓 하지 말라는 거에요</p>
<p>디자인 패턴과 성능은 별개에요. </p>
<p>디자인 패턴은 코드의 가독성과 유지보수를 위해 객체의 메서드를 분리합니다. 분리로 인하여 호출도 자주 발생하겠죠?? </p>
<p>함수 호출과 객체간 호출은 적을수록 성능이 좋답니다 그러니까 너무 많이 사용하지말고 적절히 사용해야 한다는 뜻이에요.</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>디자인 패턴이 무엇인지 알아보았어요. 이제 다음부터는 생성, 구조, 행동 패턴에 대해 알아보고 코드를 구현해볼거에요.</p>
<p>참고로 이 책은 PHP로 쓰였습니다.
듣기만하던 php를 책으로 먼저 실습할 줄 몰랐는데,,
아무튼 열심히 해볼게요.</p>
<h3 id="리팩토링이나-클린코드부터-읽어야하는거-아니에요">리팩토링이나 클린코드부터 읽어야하는거 아니에요?</h3>
<p>클린 코드는 가독성을 위해, 리팩토링은 코드의 유지보수를 위해 읽는다고 생각합니다. </p>
<p>그렇기때문에 클린코드를 뛰어넘고, 패턴에 대해 공부한 후, 리팩토링을 공부하는게 도움되는 순서일 것이라고 판단했습니다.</p>
<p>뭐 읽어서 나쁜건 없지만~ 바쁘다 바빠 현대사회에서 적당한 생략과 선택은 가능하지 않은가요?</p>
<p>나름의 변명같기도 하네요. 제 생각은 그렇다,, 입니다~ 책을 선택한 이상, 이 책을 열심히 읽고 공부해야겠죠? 마무리하고 공부하러 가겠습니다. 화이팅! O(｀・∀・´)○ </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[42seoul] push_swap 무찌르기]]></title>
            <link>https://velog.io/@min_gi1123/42seoul-pushswap-%EA%B8%B0%EA%B9%94%EB%82%98%EB%8A%94-%EC%A0%9C%EB%AA%A9</link>
            <guid>https://velog.io/@min_gi1123/42seoul-pushswap-%EA%B8%B0%EA%B9%94%EB%82%98%EB%8A%94-%EC%A0%9C%EB%AA%A9</guid>
            <pubDate>Tue, 15 Nov 2022 07:18:05 GMT</pubDate>
            <description><![CDATA[<p>2서클 과제중 가장 어렵다는 push_swap을 Greedy로 해결한 이야기에 대해 기제하고자 합니다.</p>
<ul>
<li>서브젝트 한글 번역본
<a href="https://github.com/42seoul-translation/subject_ko/blob/master/push_swap/push_swap.ko.md">https://github.com/42seoul-translation/subject_ko/blob/master/push_swap/push_swap.ko.md</a></li>
</ul>
<h2 id="서론">서론</h2>
<p>작성하는 이유는 </p>
<ol>
<li>push_swap을 그리디로 풀이한 글이 별로 없어서</li>
<li>내 코드 자랑할라고</li>
<li>블랙홀 빠지기 전, 42글 하나는 올리려고,,,</li>
</ol>
<p>처음에는 그냥 머지소트로 작업하려 했으나,, 100점이 안 나온다더라고요?
다른분들은 거의 투 피벗 퀵소트나 모래시계 알고리즘을 사용하셨습니다.
다 하는거 싫어서 주위에 여쭈어봤더니 &quot;그리디&quot;로 하신분이 계셨습니다.
저의 푸시스왑 선생님의 설명을 참고해서 해결하게 되었습니다.</p>
<hr>
<h2 id="그리디">그리디</h2>
<p>Greedy 알고리즘은 &quot;순간순간 최적의 선택&quot;을 합니다.
매 순간 최적의 경우를 선택하기 때문에 그 과정 자체가 최적화입니다.
다른 알고리즘을 이용한 경우, 명령어들을 모두 다른 리스트에 담았다가 최적화를 시켜주시던데. 그리디는 그럴 필요 없습니다. 개쩔조?</p>
<hr>
<h2 id="로직">로직</h2>
<p>목차만 작성해보고 뒤에 천천히 설명해볼게요.</p>
<ol>
<li>argv 읽어서 deque에 init 하고, 정렬된 배열하나 만들어서 data를 인덱스로 교체</li>
<li>스택 a에 원소 3개가 남을때까지 b에 push하고, 스택 a 정렬하기 (3개 하드코딩)</li>
<li>Greedy 시작. 스택 b가 빌 때 까지 스택 b의 모든 원소들이 스택a의 올바른 위치에 이동할 때,필요하 ㄴ연산 횟수를 모두 계산하여 가장 작은 값을 가진 원소 하나만 b에서 a로 push</li>
<li>스택 b가 비었으면, 스택 a에서 0을 찾아서 0이 front가 되도록 만들어 줌</li>
</ol>
<p>끝 입니다. 간단하지요?</p>
<hr>
<h2 id="0-구조--명령어">0. 구조 &amp; 명령어</h2>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/258ea4b5-c66d-4cd4-b375-572437532da0/image.png" alt=""></p>
<p>양방향 연결리스트로 구현하였습니다. 그래서 이름도 deque 입니다.
구조체는 이렇게 2개 썼어요.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/9ec41c45-cad7-4133-9aaa-be202529a4e3/image.png" alt=""></p>
<p>deque의 이름에 맞게 명령어들을 구현에 주었습니다.
서브젝트에 제시된 명령어에 deque command를 그대로 사용했습니다.</p>
<hr>
<h2 id="1-파싱">1. 파싱</h2>
<p>이 부분은 개인이 구현하기 나름이라고 생각합니다. 저는 이렇게 했다..</p>
<ol>
<li>argv 읽어서 스택 a에 push_back</li>
<li>동시에 int 형 arr배열에 저장</li>
<li>arr배열 정렬해서 스택 a의 data값을 정렬된 배열의 인덱스로 교체</li>
</ol>
<p><strong>제 핵심은 &quot;인덱스 값으로 교체&quot;하는 것 입니다.</strong></p>
<blockquote>
<p>이렇게 해도 됨?</p>
</blockquote>
<p>ㅇㅇ 이 서브젝트는 들어온 인자를 정렬하는 <strong>&quot;명령어를 출력&quot;</strong>하는게 목표이기 때문에, 들어온 인자를 재사용하지 않음!!</p>
<p>인자가 ./push_swap 5 9 7 2 1
이렇게 들어왔다면 
이제 <strong>2 4 3 1 0</strong> 으로 바꾸어주는 것.</p>
<blockquote>
<p>이렇게 하면 뭐가 좋은가요!</p>
</blockquote>
<ol>
<li>마지막에 정렬 할 때 가장 작은 값은 무조건 0이라서 편함</li>
<li>분할 파트에서 보면 pivot 정할때 편함</li>
</ol>
<p>이 부분을 평가에서 칭찬받아서 기분이 좋았어요</p>
<hr>
<h2 id="2-분할">2. 분할</h2>
<p>다른 분들이 투 피벗 퀵소트를 많이 하신다고들 하시던데, 그 부분을 참고하여 분할합니다.</p>
<p>저의 선생님께서 참고하신 글이 <a href="https://techdebt.tistory.com/26">https://techdebt.tistory.com/26</a> 이 글 이라고 하셨어요. 
어.. 저의 두번째 선생님입니다. 도움을 많이 받았습니다.
어,, 근데 제가 설명하려는 말들이 다 여기에 있네요.</p>
<ol>
<li>pivot 2개를 설정해서 3분할</li>
<li>스택 a에는 pivot2보다 큰 원소만 남아있음.</li>
<li>스택 a에 3개만 남겨놓고 전부 b로 push</li>
<li>스택 a에 남은 3개 하드코딩</li>
</ol>
<p>까지가 그리디 직전까지의 준비입니다.</p>
<p>여기서 왜 3분할을 해준후에 다 넘겨주나면, 3분할 해서 큰 집합의 순서대로 정렬하기 위함입니다. 이 부분은 직접 실행해보시거나, 두번째 선생님의 유튜브를 보시면 알 수 있습니다.
분할을 해주는 과정이 이후에 정렬을 하게 될 때, rb와 rrb를 적게 해주는 요인이 됩니다.</p>
<hr>
<h2 id="3-그리디">3. 그리디</h2>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/7d1a71b2-b7e8-48ec-9849-eb1dca498f22/image.png" alt=""></p>
<p>전체적인 정리는,,
스택 b가 빌때까지 반복 b-&gt;a로 이동할 때, 가장 적은 명령을 이용하는 원소를 찾아서 push해주는 것</p>
<p><strong>이 때 중요한게, a는 0이 가장 위가 아닐 뿐, 항상 정렬된 상태여야합니다.</strong></p>
<p>그래서 우리는 b에서 a로 push 할 때, 앞 원소보다 크고 뒷 원소보다는 작은 위치에 정확히 push 할거에요.</p>
<p>예시를 들자면</p>
<blockquote>
<p>a : 13 20 4 10 12</p>
</blockquote>
<p>a스택이 이렇다고 합시다. 지금 4가 중간에 있지만, 4 10 13 15 20 순으로 정렬되어있죠? </p>
<blockquote>
<p>b : 14 7</p>
</blockquote>
<p>여기서 경우를 따져볼게요.</p>
<h3 id="--14를-push하는-경우">- 14를 push하는 경우</h3>
<blockquote>
<p>a : 20 4 10 12 13
b : 14 7</p>
</blockquote>
<p>이 상태로 만들어서 push를 해야겠죠 </p>
<blockquote>
<p>a : 14 20 4 10 12 13
b : 7</p>
</blockquote>
<p>이 상태가 됩니다. 
a에서는 ra1번, b에서 0번, 총 명령어 사용 횟수 1번입니다.</p>
<h3 id="--7을-push-하는-경우">- 7을 push 하는 경우</h3>
<blockquote>
<p>a : 10 12 13 20 4
b : 7 14</p>
</blockquote>
<p>이 상태로 만들어서 push를 해주면 </p>
<blockquote>
<p>a : 7 10 12 13 20 4
b : 14</p>
</blockquote>
<p>이 상태가 되는거고, a에서는 rra 2번, b에서 ra 1번 총 명령어 사용 횟수 3번입니다.</p>
<p>그렇다면 14를 push할때가 7을 push할 때 보다 1번 &lt; 3번으로 더 적어서, 14를 push 하게 됩니다.</p>
<p>이 과정을 스택 b가 빌 때 까지 계속 반복.</p>
<p>상세 함수들에 대해 설명을 해볼게요.</p>
<h3 id="find_best">find_best</h3>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/9a080650-6db1-4afd-9388-df257956cf68/image.png" alt=""></p>
<p>스택b의 front부터 back까지, 이 원소가 a로 이동하려면 명령어를 얼마나 써야하는지 계산함.
이거 할 때, 스택사이즈 반을 넘어가면 rb하는 것 보다 rrb하는게 더 이득이잖아요. 그래서 그 부분은 이제 + 랑 - 로 분류를 해주었습니다.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/ea4dbd6d-e92f-480f-b517-0e0962b239f0/image.png" alt=""></p>
<p>스택 b에 있는 원소가 스택 a에 들어갈 때, 알맞은 자리를 찾는 함수입니다. </p>
<p>뭐,, 상당히 더럽고 마음에 안들어요. 그치만 이 부분에 대한 코드를 찾기가 어려워서 제 더러운 코드를 올립니다.
제가 front-&gt;prev=NULL, back-&gt;next=NULL로 설정했기 때문에, NULL을 역참조 하지 않도록하다보니 더러워졌습니다.
<del>어쩔수 없었어요 블랙홀 1열이었다구요</del></p>
<h3 id="before_push-어쩌고">before_push 어쩌고</h3>
<p>push 상태로 스택a랑 스택b를 변경
스택 a와 b를 같은 방향으로 동시에 돌려주는게 _all
각각 돌려주는건 _single</p>
<h3 id="last_sort">last_sort</h3>
<p>스택b는 비어있고, 스택a는 정렬된 상태이지만, 0이 중간 어딘가에 있을거임. 0이 가장 상단에 위치하도록 rotate함.</p>
<hr>
<h2 id="정리-및-회고">정리 및 회고</h2>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/6e885dd7-f9c4-4da7-8dea-df83d8999790/image.png" alt=""></p>
<p>100개 5점 기준 700개 통과!</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/ae3f26a6-cc68-4be9-bcf3-061cee9e7d39/image.png" alt=""></p>
<p>500개 5점 기준 5500개 통과!</p>
<p>뿌듯한 사람입니다.
그치만 시간이 촉박했던만큼, 더 가독성 좋고, 줄일만한거 더 줄인 코드를 포기했음이 아쉽습니다.</p>
<p>푸시스왑 선생님 승훈님과 푸시스왑을 케이크처럼 퍼먹는 방법을 올려주신.. 선생님의 인트라 네임을 알고싶어요 감사합니다!!!
그리고 새벽에 같이 에러 잡아주신 조주님이랑 첫 평가자로 와주셔서 많은 것을 가르쳐주고 칭찬해주신 썬박님 감사합니다</p>
<p>근데 이렇게 냅다 이름 적어도 괜찮은건가요? 감사하다고 말 하기 부끄러우니까 허공에 외치는거죠 ㅇㅇ </p>
<p>푸시스왑 끗</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] 백준 12015 가장 긴 증가하는 부분 수열 2 (최장 증가 부분 수열 / LIS / Longest Increasing Subsequence / 이분 탐색 / binary search / nlogn)]]></title>
            <link>https://velog.io/@min_gi1123/c</link>
            <guid>https://velog.io/@min_gi1123/c</guid>
            <pubDate>Tue, 01 Nov 2022 18:26:09 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/12015">https://www.acmicpc.net/problem/12015</a></p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/3337883c-45cc-41db-b372-ba14ea45b1c4/image.png" alt=""></p>
<h3 id="lis-longest-increasing-subsequence">LIS (Longest Increasing Subsequence)</h3>
<blockquote>
<p>주어진 <strong>&#39;수열&#39;</strong> 에서 일부 원소를 뽑아내어 새로만든 수열이 <strong>&#39;부분 수열&#39;</strong> 
이 수열이 <strong>&#39;오름차순&#39;</strong> 인 수열이 <strong>&#39;증가하는 부분 수열&#39;</strong> 이 된다. 
만들 수 있는 오름차순 수열 중, <strong>&#39;가장 긴&#39;</strong> 수열이 <strong>LIS</strong>가 된다.</p>
</blockquote>
<h3 id="before-solution">Before Solution</h3>
<blockquote>
<p>DP VS <strong>Binary Search</strong></p>
</blockquote>
<p>블로그를 기제하는 이유중 핵심은 &quot;Binary Search&quot;. 즉, 이분탐색 때문이다.
LIS 유형은 DP로도 풀 수 있고, Binary Search로도 풀 수 있다.</p>
<p>이 전에 가장 증가하는 긴 부분 수열 문제(<a href="https://www.acmicpc.net/problem/11053)%EB%A5%BC">https://www.acmicpc.net/problem/11053)를</a> 풀 때, DP로 풀었어서, 이 문제도 똑같이 풀었으나 &quot;시간초과&quot;가 난다. </p>
<p>*<em>이유는 DP로 풀면 O(N^2)이지만, 이분 탐색으로 풀면 O(NlogN)만큼 걸리기 때문 *</em></p>
<p>+)DP풀이는 상당히 간단함. dp배열 만들어서 이중for문 돌리면 됨</p>
<h3 id="solution">Solution</h3>
<blockquote>
<p>&#39;a배열의 원소&#39;와 &#39;lis배열의 마지막 원소&#39;를 비교 O(N)
    -&gt; 더 크다면 lis배열의 마지막에 추가.
    -&gt; 작다면 <strong>Binary Search</strong>를 이용하여 자리 탐색 O(logN)</p>
</blockquote>
<p>그림으로 보면 훨씬 이해하기 편하다.
<img src="https://velog.velcdn.com/images/min_gi1123/post/afd3d9f9-7904-4b3b-bb9d-4dfa8d861f37/image.jpg" alt=""></p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/a96d9c14-b90c-4807-a743-8c6e56da76f2/image.jpg" alt=""></p>
<p>첨언하자면 큰 값이면 뒤에 추가하고, 큰 값 보다 작은 값이면 적절한 자리를 찾아서 넣어준다.
증가하는 부분수열 {1,3,9}와 {1,3,5}가 있을때, 두 수열의 길이는 3으로 동일하다. 하지만 <strong>&quot;가장 긴&quot;</strong> 증가하는 부분 수열을 만들려면, 가장 뒤 원소가 최솟값인게 유리 할 것이다.
그러니까 뒤에 원소가 7일때 {1,3,9} 뒤에는 7을 못 붙이는데 {1,3,5}뒤에는 7을 붙일 수 있다는 뜻.
이해가 안 간다면 직접 손으로 계산해보길 바란다.</p>
<pre><code class="language-cpp">int j = 0;
    lis[0] = a[0];
    for (int i=0; i&lt;n; i++){
        if (lis[j] &lt; a[i]){
            lis[j+1] = a[i];
            j++;
        }
        else{
            int idx = binarysearch(0, j, a[i]);
            lis[idx] = a[i];
        }
    }</code></pre>
<h3 id="binary-search">Binary Search</h3>
<blockquote>
<p><strong>정렬되어 있는 배열</strong> left ~ right 사이의 <strong>중간위치 mid</strong>를 구하여 array[mid]의 값과 타겟을 비교한다.
-&gt; 타겟이 mid의 값보다 작다면 : right = mid
-&gt; 타겟이 mid의 값보다 크다면 : left = mid + 1;
시간복잡도가 O(logN)</p>
</blockquote>
<p>lis배열은 정렬되어있는 배열이기때문에 이분탐색으로 적절한 위치를 찾을 수 있다.
이분 탐색에 대해 이해가 안간다면 따로 알아보자.</p>
<pre><code class="language-cpp">int binarysearch(int left, int right, int target){
    int mid;
    while (left &lt; right){
        mid = (left + right)/2;

        if (lis[mid] &lt; target)
            left = mid + 1;
        else
            right = mid;
    }

    return right;
}</code></pre>
<p>이게 끝이다. 
생각보다 간단함!</p>
<h3 id="전체코드">전체코드</h3>
<pre><code class="language-cpp![](https://velog.velcdn.com/images/min_gi1123/post/369b3745-da97-4478-a873-441fb54619fc/image.png)">
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
using namespace std;

int n,a[1000005]={0,},lis[1000005]={0,};

int binarysearch(int left, int right, int target){
    int mid;
    while (left &lt; right){
        mid = (left + right)/2;

        if (lis[mid] &lt; target)
            left = mid + 1;
        else
            right = mid;
    }

    return right;
}

int main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    cin&gt;&gt;n;
    for(int i=0; i&lt;n; i++)
        cin&gt;&gt;a[i];

    int j = 0;
    lis[0] = a[0];
    for (int i=0; i&lt;n; i++){
        if (lis[j] &lt; a[i]){
            lis[j+1] = a[i];
            j++;
        }
        else{
            int idx = binarysearch(0, j, a[i]);
            lis[idx] = a[i];
        }
    }

    cout&lt;&lt;j+1;

    return 0;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/6244fb49-d985-463e-a15e-0f7e240c5bc6/image.png" alt=""></p>
<p>dp로 풀면 시간초과납니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] 백준 2206 벽 부수고 이동하기]]></title>
            <link>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-2206-%EB%B2%BD-%EB%B6%80%EC%88%98%EA%B3%A0-%EC%9D%B4%EB%8F%99%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-2206-%EB%B2%BD-%EB%B6%80%EC%88%98%EA%B3%A0-%EC%9D%B4%EB%8F%99%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 05 Oct 2022 03:59:39 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/2206">https://www.acmicpc.net/problem/2206</a></p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/5c2875f3-506e-4a33-9741-b60a7fe27e7b/image.png" alt=""></p>
<h2 id="bfs-응용">BFS 응용</h2>
<p>bfs로 바로 풀 수 있다. 
다만 조건식이 조금 복잡하여 올리고자 한다.</p>
<h2 id="구조체">구조체</h2>
<pre><code class="language-cpp">typedef struct {
    int x;
    int y;
    int blk; ///벽을 뚫을 수 있는 횟수
} pos;</code></pre>
<p>큐에 좌표값과 벽을 뚫었는지 안 뚫었는지의 여부를 저장해야하는데, pair을 두번 쓰기 싫어서 구조체를 만들어버렸다.</p>
<h2 id="조건문">조건문</h2>
<pre><code class="language-cpp">//갈인데 (0) 안 갔음
        if (x != (n - 1) &amp;&amp; map[x + 1][y] == 0 &amp;&amp; v[x + 1][y][blk] == 0) {
            v[x + 1][y][blk] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x + 1;
            temp.y = y;
            temp.blk = blk;
            q.push(temp);
        }
        //벽인데 (1) 아직 안 뚫었음
        if (x != (n - 1) &amp;&amp; map[x + 1][y] == 1 &amp;&amp; blk == 1) {
            v[x + 1][y][blk - 1] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x + 1;
            temp.y = y;
            temp.blk = blk - 1;
            q.push(temp);
        }
</code></pre>
<p>두 조건문이 다름을 알아야한다.</p>
<ul>
<li>길이 0 일때
v[x + 1][y][blk] = v[x][y][blk] + 1;</li>
<li>길이 1 일때 (벽)
v[x + 1][y][blk - 1] = v[x][y][blk] + 1;</li>
</ul>
<p>적고보니 이게끝이다. 상당히 쉬운데 귀찮은 문제였다.
오랜만에 백준 푼 김에 업로드 한다.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;queue&gt;
#include &lt;stdio.h&gt;

using namespace std;

typedef struct {
    int x;
    int y;
    int blk; ///벽을 뚫을 수 있는 횟수
} pos;

queue&lt;pos&gt; q;

int n, m,
    map[1005][1005] = {0,},v[1005][1005][2] = {0,};

int bfs() {
    pos p;
    p.x = 0;
    p.y = 0;
    p.blk = 1;
    v[0][0][1]=1;
    q.push(p);

    while (!q.empty()) {
        int x = q.front().x;
        int y = q.front().y;
        int blk = q.front().blk;
        q.pop();
//        cout&lt;&lt;x&lt;&lt;&quot; &quot;&lt;&lt;y&lt;&lt;&quot; &quot;&lt;&lt;blk&lt;&lt;&quot;\n&quot;;

        if (x == n -1 &amp;&amp; y == m -1)
            return v[x][y][blk];

        //갈인데 (0) 안 갔음
        if (x != (n - 1) &amp;&amp; map[x + 1][y] == 0 &amp;&amp; v[x + 1][y][blk] == 0) {
            v[x + 1][y][blk] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x + 1;
            temp.y = y;
            temp.blk = blk;
            q.push(temp);
        }
        //벽인데 (1) 아직 안 뚫었음
        if (x != (n - 1) &amp;&amp; map[x + 1][y] == 1 &amp;&amp; blk == 1) {
            v[x + 1][y][blk - 1] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x + 1;
            temp.y = y;
            temp.blk = blk - 1;
            q.push(temp);
        }

        // 2
        if (x != 0 &amp;&amp; map[x - 1][y] == 0 &amp;&amp; v[x - 1][y][blk] == 0) {
            v[x - 1][y][blk] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x - 1;
            temp.y = y;
            temp.blk = blk;
            q.push(temp);
        }
        if (x != 0 &amp;&amp; map[x - 1][y] == 1 &amp;&amp; blk == 1) {
            v[x - 1][y][blk-1] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x - 1;
            temp.y = y;
            temp.blk = blk - 1;
            q.push(temp);
        }

        // 3
        if (y != (m - 1) &amp;&amp; map[x][y + 1] == 0 &amp;&amp; v[x][y + 1][blk] == 0) {
            v[x][y + 1][blk] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x;
            temp.y = y + 1;
            temp.blk = blk;
            q.push(temp);
        }
        if (y != (m - 1) &amp;&amp; map[x][y + 1] == 1 &amp;&amp; blk == 1) {
            v[x][y + 1][blk -1] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x;
            temp.y = y + 1;
            temp.blk = blk -1;
            q.push(temp);
        }

        // 4
        if (y != 0 &amp;&amp; map[x][y - 1] == 0 &amp;&amp; v[x][y - 1][blk] == 0) {
            v[x][y - 1][blk] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x;
            temp.y = y - 1;
            temp.blk = blk;
            q.push(temp);
        }
        if (y != 0 &amp;&amp; map[x][y - 1] == 1 &amp;&amp; blk == 1) {
            v[x][y - 1][blk-1] = v[x][y][blk] + 1;
            pos temp;
            temp.x = x;
            temp.y = y - 1;
            temp.blk = blk -1;
            q.push(temp);
        }
    }
    return -1;
}

int main() {
    cin &gt;&gt; n &gt;&gt; m;
    for (int i = 0; i &lt; n; i++) {
        for (int j = 0; j &lt; m; j++) {
            scanf(&quot;%1d&quot;, &amp;map[i][j]);
        }
    }

    cout&lt;&lt;bfs();

    return 0;
}
</code></pre>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/9a1c56ce-5772-4ecd-bda5-a2b25a546a8a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] Programmers - PCCP 모의고사 1회 3번 유전법칙]]></title>
            <link>https://velog.io/@min_gi1123/c-Programmers-PCCP-%EB%AA%A8%EC%9D%98%EA%B3%A0%EC%82%AC-1%ED%9A%8C-3%EB%B2%88-%EC%9C%A0%EC%A0%84%EB%B2%95%EC%B9%99</link>
            <guid>https://velog.io/@min_gi1123/c-Programmers-PCCP-%EB%AA%A8%EC%9D%98%EA%B3%A0%EC%82%AC-1%ED%9A%8C-3%EB%B2%88-%EC%9C%A0%EC%A0%84%EB%B2%95%EC%B9%99</guid>
            <pubDate>Fri, 16 Sep 2022 21:48:07 GMT</pubDate>
            <description><![CDATA[<p>PCCP 모의고사 1회 3번
[PCCP 모의고사 #1] 유전법칙</p>
<p>점화식을 세워서 푸는 문제! 난이도는 쉬운편.
백준으로 치면 실버 2~ 정도의 문제일 듯 함
좋아하는 형식의 문제라서 굳이 올린다.</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/7e183af1-bdc6-4405-bc37-45988d2df58a/image.png" alt=""></p>
<p>[세대,차례] 의 형식으로 주어진다.
n번째 세대의 p번째 차례의 완두콩의 유전형식을 구하는 문제.
정말 단순하다!!</p>
<h2 id="코드">코드</h2>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;cmath&gt;

using namespace std;

int cong[5]={0,0,1,1,2};

int dfs(int a, int b){

    if (a == 2){
        return cong[b];
    }

    int x = b/4;
    int y = b%4;
    if (y!=0)
        x++;

    int n = dfs(a-1,x);

    if (n == 0)
        return 0;
    else if (n == 2)
        return 2;
    else {
        if (y == 1)
            return 0;
        else if (y == 0)
            return 2;
        else
            return 1;
    }
}

vector&lt;string&gt; solution(vector&lt;vector&lt;int&gt;&gt; queries) {
    vector&lt;string&gt; answer;

    for (int i=0; i&lt;queries.size(); i++){
        int a = queries[i][0];
        int b = queries[i][1];

        if (a == 1){
            answer.push_back(&quot;Rr&quot;);
            continue;
        }

        int n = dfs(a,b);

        if (n == 0)
            answer.push_back(&quot;RR&quot;);
        else if (n == 2)
            answer.push_back(&quot;rr&quot;);
        else
            answer.push_back(&quot;Rr&quot;);

    }

    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] Programmers - PCCP 모의고사 1회 2번 체육대회]]></title>
            <link>https://velog.io/@min_gi1123/c-Programmers-PCCP-%EB%AA%A8%EC%9D%98%EA%B3%A0%EC%82%AC-1-%EC%B2%B4%EC%9C%A1%EB%8C%80%ED%9A%8C</link>
            <guid>https://velog.io/@min_gi1123/c-Programmers-PCCP-%EB%AA%A8%EC%9D%98%EA%B3%A0%EC%82%AC-1-%EC%B2%B4%EC%9C%A1%EB%8C%80%ED%9A%8C</guid>
            <pubDate>Fri, 16 Sep 2022 16:28:59 GMT</pubDate>
            <description><![CDATA[<p>PCCP 모의고사 1회 2번
[PCCP 모의고사 #1] 체육대회</p>
<p>9월 18일 일요일 PCCP 준비를 위해 모의고사를 풀어보는중
알 것 같은 문제의 구현이 어려워서 고민하고있는데
예지 언니가 이거 <strong>&quot;N퀸 아니야?&quot;</strong> 라고 하는것이다....
와 라피신 코드 바로 뒤져서 풀었다!! <del>이 언니는 천재야 언니 생일축하해^^</del></p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/71052e0b-ad55-4e47-bd28-4ba220e02473/image.png" alt=""></p>
<p>대표를 뽑는 문제이다. 다만 2차원 배열이라 조합에 어려움을 느낄 수 있다.</p>
<h3 id="백준-9663-n-queen">백준 9663 N-Queen</h3>
<p><a href="https://www.acmicpc.net/problem/9663">https://www.acmicpc.net/problem/9663</a></p>
<p>유사한 문제를 첨부한다.
N-Queen을 푼 사람이라면 바로 감을 잡을 수 있을것이다. == <strong>먼저 풀고와라.</strong>
라피신때 코드가 도움이 되다니요 역시 42서울은 내 인생에 도움이 된다니까</p>
<h2 id="solution">Solution</h2>
<p>dfs를 이용하여 index를 오른쪽으로 옮겨갈 것이다. 한 경우를 모두 다 찾았으면 최댓값을 갱신해준다.
이 때, 한 사람을 중복으로 체크하지않도록 v 배열을 만들어 체크하였다.</p>
<h2 id="2차원-vector-함수-전달">2차원 vector 함수 전달</h2>
<p>보낼때</p>
<pre><code class="language-cpp">int solution(vector&lt;vector&lt;int&gt;&gt; ability) {
    dfs (ability,0);</code></pre>
<p>받을때</p>
<pre><code class="language-cpp">void dfs(vector&lt;vector&lt;int&gt;&gt; &amp;ability, int index){</code></pre>
<p>근데 이 전달방법은 Call by Value라고 한다. Call by Reference를 하려면 &amp;를 빼면 된다고 하는 것 같은데, 더 찾아보겠다.</p>
<h3 id="수행시간">수행시간</h3>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/4348a248-40f4-4f42-815b-ffc516a1dab1/image.png" alt=""></p>
<p>뿌듯!!</p>
<h2 id="소스-코드">소스 코드</h2>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;

using namespace std;

int v[10] = {0,};
int mymax = 0,sum = 0;

void dfs(vector&lt;vector&lt;int&gt;&gt; &amp;ability, int index){

    if (index == ability[0].size()){ //한 경우를 다 찾았으면 합산
        if (mymax &lt; sum)
            mymax = sum;
        return ;
    }

    for (int i=0; i&lt;ability.size(); i++){
        if (v[i] == 1)
            continue;
        v[i]=1;
        sum += ability[i][index];
        dfs(ability,index+1);
        sum -= ability[i][index];
        v[i]=0;
    }
}

int solution(vector&lt;vector&lt;int&gt;&gt; ability) {
    int answer = 0;

    dfs (ability,0);
    answer = mymax;

    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] Programmers - 다단계 칫솔 판매]]></title>
            <link>https://velog.io/@min_gi1123/c-Programmers-%EB%8B%A4%EB%8B%A8%EA%B3%84-%EC%B9%AB%EC%86%94-%ED%8C%90%EB%A7%A4</link>
            <guid>https://velog.io/@min_gi1123/c-Programmers-%EB%8B%A4%EB%8B%A8%EA%B3%84-%EC%B9%AB%EC%86%94-%ED%8C%90%EB%A7%A4</guid>
            <pubDate>Wed, 14 Sep 2022 09:56:27 GMT</pubDate>
            <description><![CDATA[<p>2021 Dev-Matching: 웹 백엔드 개발자(상반기)
Lv.3 다단계 칫솔 판매</p>
<p>  <img src="https://velog.velcdn.com/images/min_gi1123/post/0f79b358-2c9d-4889-8b19-28f611dcd09f/image.png" alt=""></p>
<blockquote>
<p>map 을 이용하여 재귀호출하는 문제!</p>
</blockquote>
<p>단순히 추천인을 찾아가며 10퍼센트의 이익을 더해주는 문제이다.
그러나 시간초과로 계속 고생했는데,, 그 이유에는 여러가지 요인이있다.
간단히만 정리하자면</p>
<h3 id="1-map을-사용할-것">1. MAP을 사용할 것.</h3>
<ul>
<li>처음에는 index의 값을 저장하여 find함수를 이용하여 풀었으나, map을 사용하니 시간복잡도가 획기적으로 낮아짐 (map의 시간복잡도가 logN이라고 한다.)</li>
</ul>
<h3 id="2-10의-이익이-1-미만일때-호출-멈추기">2. 10%의 이익이 1 미만일때 호출 멈추기</h3>
<ul>
<li>최대 재귀 호출에 1000번정도의 제한되어 있기 때문!!</li>
<li>최악의 경우 (일직선 트리일 때 ) 불필요한 호출이 계속 될 수 있음</li>
</ul>
<p>이것만 명시하면 난이도가 높을 문제는 아닐 듯 하다.
내가 MAP에 대한 지식이 부족했었던터라, 공부하여 앞으로의 문제에서 자주 활용 할 필요가 있을 듯 하다.</p>
<h2 id="처음-코드-1113-케이스에서-time-out">처음 코드 (11~13 케이스에서 Time Out)</h2>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;

using namespace std;

vector&lt;int&gt; solution(vector&lt;string&gt; enroll, vector&lt;string&gt; referral, vector&lt;string&gt; seller, vector&lt;int&gt; amount) {
    vector&lt;int&gt; answer;

    //정답 배열 셋팅
    for (int i=0; i&lt;enroll.size(); i++)
        answer.push_back(0);

    //seller 한 명 씩 계산
    for (int k=0; k&lt;seller.size(); k++){
        string name = seller[k];
        int cost = amount[k]*100;

        //10%
        int per = cost / 10;
        cost -= per;

        int index = find(enroll.begin(), enroll.end(), name) - enroll.begin();

        while(cost != 0){ //반복

            answer[index] += cost;

            if (per &lt; 1)
                break;

            //10%
            cost = per;
            per = cost / 10;
            cost -= per;

            //추천인 x
            if (referral[index] == &quot;-&quot;)
                break;

            //다음 추천인
            index = find(enroll.begin(), enroll.end(), referral[index]) - enroll.begin();
        }

    }

    return answer;
}</code></pre>
<h2 id="정답-코드">정답 코드</h2>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;map&gt;

using namespace std;

map &lt;string, int&gt; me;
map &lt;string, string&gt; par;

void dfs(string name, int cost){
    if (name == &quot;-&quot;) return ;
    int ten = cost / 10;
    me[name] += cost - ten;

    if (ten &gt; 0) dfs(par[name],ten);
}

vector&lt;int&gt; solution(vector&lt;string&gt; enroll, vector&lt;string&gt; referral, vector&lt;string&gt; seller, vector&lt;int&gt; amount) {
    vector&lt;int&gt; answer;

    for (int i=0; i&lt;enroll.size(); i++){
        me[enroll[i]]=0;
        par[enroll[i]] = referral[i];
    }

    for (int i=0; i&lt;seller.size(); i++){
        dfs(seller[i],amount[i]*100);
    }

    for (int i=0; i&lt;enroll.size(); i++){
        answer.push_back(me[enroll[i]]);
    }

    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[데보션 영 1기 발대식]]></title>
            <link>https://velog.io/@min_gi1123/%EB%8D%B0%EB%B3%B4%EC%85%98-%EC%98%81-1%EA%B8%B0-%EB%B0%9C%EB%8C%80%EC%8B%9D</link>
            <guid>https://velog.io/@min_gi1123/%EB%8D%B0%EB%B3%B4%EC%85%98-%EC%98%81-1%EA%B8%B0-%EB%B0%9C%EB%8C%80%EC%8B%9D</guid>
            <pubDate>Fri, 26 Aug 2022 13:13:01 GMT</pubDate>
            <description><![CDATA[<h2 id="--devocean-young">- DEVOCEAN YOUNG</h2>
<p>DEVOCEAN YOUNG 1기 포스터
<img src="https://velog.velcdn.com/images/min_gi1123/post/40f542ae-92f7-40b6-8b69-9ca6fc9240ca/image.png" alt="">
sccc 단톡방에 올라왔는데, 포스터 보고 바로 신청했다. SK?! 너무너무 하고싶었음!!</p>
<h2 id="-devocean">-DEVOCEAN</h2>
<p><a href="https://devocean.sk.com">https://devocean.sk.com</a></p>
<p> SK에서 운영하는 개발자 커뮤니티!</p>
<h2 id="-합격">-합격</h2>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/86dd20f3-e4f1-4c39-a73a-3d73349d4549/image.png" alt=""></p>
<p>합격 문자</p>
<h2 id="-발대식">-발대식</h2>
<p>2022/07/07 금</p>
<table>
  <tr>
    <td style="border-top: hidden; border-left: hidden; border-right: hidden;"><img alt="" src="https://velog.velcdn.com/images/min_gi1123/post/eb60d85c-a98a-472a-86f3-3823dc0109b4/image.png" /></td><td style="border-top: hidden; border-right: hidden;"><img alt="" src="https://velog.velcdn.com/images/min_gi1123/post/ce0d0628-9847-4dff-9d26-c61961d958c2/image.png" /></td>
  <tr>
</table>

<p>SKT타워!!
엄청 높았다.</p>
<table>
  <tr>
    <td style="border-top: hidden; border-left: hidden; border-right: hidden;"><img alt="" src="https://velog.velcdn.com/images/min_gi1123/post/105c46c1-988a-4ca9-96a2-a768b29c7ef9/image.png" /></td><td style="border-top: hidden; border-right: hidden;"><img alt="" src="https://velog.velcdn.com/images/min_gi1123/post/39c6b05c-18af-41ba-bbab-f122da275323/image.png" /></td>
  <tr>
</table>

<p>자리에 이름표가 있었다. 맘에든다!</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/311091c2-02e7-49a3-839b-1fd8e51176db/image.png" alt=""></p>
<p>시간이 애매해서 빨리 갔는데 제일 먼저 도착해버렸다. 기다리면서 받은 샌드위치 먹었음!</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/5d635942-e47d-4e5b-907d-c985e8052baa/image.png" alt="">
HELLO! OT들었당</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/13d64cc9-d5f9-4785-b5f1-c6568ebbf6ac/image.png" alt="">
제일 왼쪽에 제가 있어요</p>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/6c595288-5f5d-43ac-a560-f08729a8913d/image.png" alt=""></p>
<p>오티가 끝난후, 다같이 치킨집으로 향했다.</p>
<p>와! 현직 개발자 마스터님들이랑 이야기했다.. 데보션 영 활동하면서 제일 궁금했던게 ‘현직 개발자님과의 만남’ 이었는데 이렇게 빨리 만나게 될 줄 몰랐다!!! 궁금했던것도 물어보고 다른 재미있는 이야기들도 하고 너무 조은 시간이었다!!!</p>
<p>Sk telecom, Sk C&amp;C, Sk 하이닉스 등.. Sk 계열사 전부 데보션에 참여하는? 그런거라고 했는데 아무튼 머찐 사람들이 많이 왔음은 확실하다.</p>
<table>
  <tr>
    <td style="border-top: hidden; border-left: hidden; border-right: hidden;"><img alt="" src="https://velog.velcdn.com/images/min_gi1123/post/62fc5453-8276-43b0-bfa8-414a897c5ca3/image.png" /></td><td style="border-top: hidden; border-right: hidden;"><img alt="" src="https://velog.velcdn.com/images/min_gi1123/post/69788a48-ec81-401c-a229-d16f54d4f310/image.png" /></td>
  <tr>
</table>

<p>선물도 받았는데 이런이런 C타입 허브를 받았다 무려 html포트도 있음! 그리고 스티커 마음에 든다</p>
<hr>
<p>음 짧고 허접한 후기이지만.. </p>
<p>발대식에서 내가 앞으로 데보션 영으로 활동하면서 여러가지 유익하고 재미있는 활동들을 할 수 있음을 알 수 있었다. 물론 내가 열심히 노력하기에 달렸다! 지금 당장의 내가 좀 더 발전해야함을 깨달았다.</p>
<p>마스터님들과 함께 활동할 동기님들과 잠깐 교류한 것 만으로도 얻어가는것이 너무 많았다. </p>
<p>마스터님들의 이야기가 너무 재미있었다. 개발 이야기도, 다른 이야기들도!! 나도 마스터님들처럼 멋진 어른이 되고싶다!!</p>
<p>모든 동기님들과 이야기를 하지는 못 했지만, 그 날 함께 이야기한 동기님들이 너무 조았다. 활동하면서 친해져서 칭구하자구 할거다. 제일 첫번째 목표~</p>
<p>아무튼 5개월간의 활동이 너무 기대되며, 열심히 활동하겠다!! 는 다짐을 하며 마무리합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] 백준 2098 외판원 순회 (Traveling Salesman problem /TSP / 비트마스킹 / bitmasking)]]></title>
            <link>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-2098-%EC%99%B8%ED%8C%90%EC%9B%90-%EC%88%9C%ED%9A%8C-Traveling-Salesman-problem-TSP-%EB%B9%84%ED%8A%B8%EB%A7%88%EC%8A%A4%ED%82%B9-bitmasking</link>
            <guid>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-2098-%EC%99%B8%ED%8C%90%EC%9B%90-%EC%88%9C%ED%9A%8C-Traveling-Salesman-problem-TSP-%EB%B9%84%ED%8A%B8%EB%A7%88%EC%8A%A4%ED%82%B9-bitmasking</guid>
            <pubDate>Sat, 16 Jul 2022 11:44:49 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/2098">https://www.acmicpc.net/problem/2098</a></p>
<img src="https://velog.velcdn.com/images/min_gi1123/post/ca892752-3959-48e1-9c37-6855c92286dd/image.png">
<img src="https://velog.velcdn.com/images/min_gi1123/post/0924928e-b348-4e8b-a1ed-b907e740ae3d/image.png">


<h3 id="외판원-순회--traveling-salesman-problem">외판원 순회 / Traveling Salesman problem</h3>
<blockquote>
<p>여러 도시들이 있고 한 도시에서 다른 도시로 이동하는 비용이 모두 주어졌을 때, 모든 도시들을 단 한 번만 방문하고 원래 시작점으로 돌아오는 최소 비용의 이동 순서를 구하는 것. 
<img src="https://velog.velcdn.com/images/min_gi1123/post/14ca0cdb-2013-4725-984f-fc9071c7569c/image.png">
조합 최적화(Combinatorial Optimization) 문제로 각 변에 가중치가 주어진 완전그래프에서 가장 작은 가중치를 가지는 &#39;해밀턴 순환&#39;을 구하는 &#39;NP-난해&#39;에 속하는 문제</p>
</blockquote>
<h3 id="solution">Solution</h3>
<blockquote>
<p><strong>비트마스킹</strong>을 이용한 <strong>dp</strong></p>
</blockquote>
<p>DP사용이유를 설명하자면 메모리와 시간복잡도때문. n이 10이하인 경우는 브루트 포스(brute force)를 이용하여 구할 수 있다. 그러나 n이 16이하인 경우는 dp를 이용하여 중복 계산을 방지해주어야 한다.</p>
<p>비트마스킹을 이용하여 방문 상태를 표시할것이다. 비스마스킹을 사용하는 이유는, 각 정점마다 다른 모든 정점들의 방문상태를 표시해야하기 때문에 메모리를 줄이기 위해 사용한다.</p>
<p>대충 말 하자면 걍 dfs랑 비슷하다.</p>
<h4 id="핵심--dp현재-방문도시방문한-도시-비트마스크에-경로값을-저장한다">핵심 : dp[현재 방문도시][방문한 도시 (비트마스크)]에 경로값을 저장한다.</h4>
<h3 id="비트마스킹">비트마스킹</h3>
<p>정수의 이진수표현을 자료구조로써 쓰는 방법. 
장점 : 빠른 실행시간, 보다 적은 메모리, 깔끔한 코드</p>
<h3 id="비트연산자">비트연산자</h3>
<p>사용한 연산자만 간단히 정리하자면</p>
<pre><code class="language-cpp">a&amp;b</code></pre>
<p>a의 모든 비트와 b의 모든 비트를 AND연산</p>
<pre><code class="language-cpp">a|b</code></pre>
<p>a의 모든 비트와 b의 모든 비트를 OR연산</p>
<h3 id="선언부">선언부</h3>
<pre><code class="language-cpp">#define INF 987654321;
int n,map[16][16];
int dp[16][1&lt;&lt;16]; //각 마을이 방문한 도시를 2진법으로 저장</code></pre>
<p>INF를 987654321로 잡았다. 더하는 연산이 있다보니 21억으로하면 오버플로우 난다. (틀렸었던 이유)
map은 이동하는 비용, dp는 총 비용</p>
<h3 id="dp배열-초기화">dp배열 초기화</h3>
<pre><code class="language-cpp">memset(dp, -1, sizeof(dp)); //dp배열 -1로 초기화</code></pre>
<p>map배열을 입력받고 dfs를 실행하기 전, dp배열을 모두 -1로 초기화한다. 방문여부를 파악하기 위함이다.</p>
<h3 id="dfs">dfs</h3>
<p>문제 조건에서 <strong>항상 순회할 수 있는 경우만 입력으로 주어진다.</strong> 라고 제시를 해주었기때문에  dfs한바퀴만 돌려도 정답이 나온다.</p>
<pre><code class="language-cpp">int dfs(int cur, int visit)</code></pre>
<p>dfs는 현재 도시 cur과 지끔까지 방문한 도시 visit을 받는다. </p>
<pre><code class="language-cpp">if (visit == (1&lt;&lt;n)-1){ //탐색 완료
        if(map[cur][0] == 0) //이동불가능
            return INF;
        return map[cur][0];
    }</code></pre>
<p> (1&lt;&lt;n)-1는 모든도시들의 방문 여부입니다. 참고로 1이 n개 (111~)</p>
<pre><code class="language-cpp">if (dp[cur][visit] != -1) //이미 탐색했으면
        return dp[cur][visit];

    dp[cur][visit] = INF;</code></pre>
<p>처음에 입력받고 dfs 실행 전에 memset을 이용하여 전부 -1로 초기화 해놓았기 때문에, -1일때만 탐색</p>
<pre><code class="language-cpp">for (int i=0; i&lt;n; i++){
        if (map[cur][i]==0) //길 X
            continue;
        if ((visit &amp; (1&lt;&lt;i)) == (1&lt;&lt;i)) //이미 방문
            continue;
        dp[cur][visit] = min(dp[cur][visit], map[cur][i] + dfs(i, visit | 1&lt;&lt;i));
    }

    return dp[cur][visit];</code></pre>
<p>가장 중요한 부분!!
먼저 해당하는 도시로 <strong>갈 수 있는지 확인</strong> 하고 <strong>방문 여부를 파악</strong>한다. 
그 다음이 핵심인데 <strong>처음시작 -&gt; 현재도시 로 가는 거리</strong>와 <strong>현재도시 -&gt; 방문하지않은 다른 도시로 가는 거리</strong> 중 작은것을 dp배열에 저장한다.
여기서  visited | (1&lt;&lt;i)를 사용하는 이유는 현재도시를 방문했다는 의미에서 사용한다.</p>
<h3 id="전체코드">전체코드</h3>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;cstring&gt;
using namespace std;

#define INF 987654321;

int n,map[16][16];
int dp[16][1&lt;&lt;16]; //각 마을이 방문한 도시를 2진법으로 저장

int dfs(int cur, int visit){

    if (visit == (1&lt;&lt;n)-1){ //탐색 완료
        if(map[cur][0] == 0) //이동불가능
            return INF;
        return map[cur][0];
    }

    if (dp[cur][visit] != -1) //이미 탐색했으면
        return dp[cur][visit];

    dp[cur][visit] = INF;

    for (int i=0; i&lt;n; i++){
        if (map[cur][i]==0) //길 X
            continue;
        if ((visit &amp; (1&lt;&lt;i)) == (1&lt;&lt;i)) //이미 방문
            continue;
        dp[cur][visit] = min(dp[cur][visit], map[cur][i] + dfs(i, visit | 1&lt;&lt;i));
    }

    return dp[cur][visit];
}

int main(int argc, const char * argv[]) {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    cin&gt;&gt;n;
    for (int i=0; i&lt;n; i++){
        for (int j=0; j&lt;n; j++){
            cin&gt;&gt;map[i][j];
        }
    }

    memset(dp, -1, sizeof(dp)); //dp배열 -1로 초기화
    cout&lt;&lt;dfs(0,1);

    return 0;
}
</code></pre>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/1cbc4fd4-35cd-4c22-aaa2-aaff7d5d37bf/image.png" alt=""></p>
<p>틀린 이유 첫번쨰는 cstring 미선언, 두번째는 INF 오버플로우</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[c++] 백준 11758 CCW (CCW / Counter Clockwise)
]]></title>
            <link>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-11758-CCW-CCW-Counter-Clockwise</link>
            <guid>https://velog.io/@min_gi1123/c-%EB%B0%B1%EC%A4%80-11758-CCW-CCW-Counter-Clockwise</guid>
            <pubDate>Sat, 25 Jun 2022 18:32:09 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/11758">https://www.acmicpc.net/problem/11758</a></p>
<img src = "https://velog.velcdn.com/images/min_gi1123/post/55c3716b-ef99-4a8f-993d-60ba2edbdd07/image.png">
<img src = "https://velog.velcdn.com/images/min_gi1123/post/3e6c14dc-24d2-43a5-b07e-1c11c3d0c988/image.png">

<h2 id="ccw--counter-clockwise">CCW / Counter Clockwise</h2>
<h3 id="ccw란">CCW란?</h3>
<blockquote>
<p>평면 위에 놓여진 세 점의 방향관계를 구할 수 있는 알고리즘
점 a,b,c를 순서대로 검사하여 반시계방향으로 놓여있으면 양수를, 시계방향이면 음수를, 평행하면 0을 리턴한다.
<img src="https://velog.velcdn.com/images/min_gi1123/post/d1ad42e3-2257-4148-bd26-643baeb9a50d/image.png">
기하 알고리즘의 한 종류입니다. </p>
</blockquote>
<h3 id="벡터의-외적">벡터의 외적</h3>
<img src="https://velog.velcdn.com/images/min_gi1123/post/925b84b3-7bb6-4d8e-8d07-2f9f24ad52b9/image.png">
외적의 결과로 외적에 쓰인 두 벡터와 동시에 수직인 벡터를 구할 수 있다.
이 수직벡터의 방향으로 세 점의 방향을 판단 할 것이다.
+) 외적은 교환법칙 성립 X (크기는 같음)
+) 단위벡터 : 길이가 1인 벡터
<img src="https://velog.velcdn.com/images/min_gi1123/post/7d746b9f-d680-4aab-af7c-4814028a7af6/image.png">
방향은 오른손 법칙을 따른다.

<p>좀 더 부가적인 설명을 해보자면, 두 벡터의 결과를 행렬식으로 나타내어보자.</p>
<img src="https://velog.velcdn.com/images/min_gi1123/post/5b36b497-4b61-4c40-9466-6295136c5764/image.png">

<p>여기서 S의 부호에 따라서 세가지로 나눈다.</p>
<ul>
<li>s &gt; 0 : 반시계방향</li>
<li>s = 0 : 일직선</li>
<li>s &lt; 0 : 시계방향</li>
</ul>
<h3 id="구조체-구현">구조체 구현</h3>
<pre><code class="language-cpp">struct pos {
    int x,y;
};</code></pre>
<p>간단하게 x,y좌표로 나타내었다. 매번 pair만 썼는데 구조체 깔끔하고 좋은 듯.</p>
<h3 id="핵심-코드">핵심 코드</h3>
<pre><code class="language-cpp">long long tmep = (b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y);</code></pre>
<p>행렬식을 그대로 이용하여 코드를 짰다. 깔끔하다.</p>
<h3 id="내-코드">내 코드</h3>
<pre><code class="language-cpp">long long temp = a.x * b.y + b.x * c.y + c.x * a.y - (b.x * a.y + c.x * b.y + a.x * c.y);</code></pre>
<p>나는 저 방법을 알기전에 신발끈 공식을 이용하여 코드를 짰다. 다만 코드가 길어지니 나도 다음부터는 위 코드를 이용할 생각이다.</p>
<h3 id="전체코드">전체코드</h3>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

struct pos {
    int x,y;
};

int main(int argc, const char * argv[]) {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    pos a,b,c;
    cin&gt;&gt;a.x&gt;&gt;a.y;
    cin&gt;&gt;b.x&gt;&gt;b.y;
    cin&gt;&gt;c.x&gt;&gt;c.y;

    long long temp = a.x * b.y + b.x * c.y + c.x * a.y - (b.x * a.y + c.x * b.y + a.x * c.y);

    if (temp &lt; 0)
        cout&lt;&lt;&quot;-1&quot;;
    else if (temp &gt; 0)
        cout&lt;&lt;&quot;1&quot;;
    else
        cout&lt;&lt;&quot;0&quot;;

    return 0;
}
</code></pre>
<p><img src="https://velog.velcdn.com/images/min_gi1123/post/ff4a779a-9fdb-41bc-aeed-f4e70574421c/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>