때는 몇일 전 이었습니다. 여느때 처럼 코드포스와 백준저지를 들락날락하며 새 문제를 풀거나 새 콘테스트가 열리는지 확인하고, 지난 못 푼 문제들 튜토리얼을 읽고 다시 풀어보고 하던 때였습니다. 모르는 사람에게 코드포스 쪽지가 와 있길래 읽어보니 다음과 같은 내용이었습니다.


새로운 온라인 저지 플랫폼인 CS Academy란 것이 있는데, 매 주 콘테스트 라운드를 연다고 합니다. 그리고 제가 코드포스에서 액티브한 유저라서 해당 사이트로 초대를 한다고 하네요..(머쓱) 아직 실력은 갈 길이 멀지만 열심히 한다고 생각해주니 고마웠습니다. 그리고 코드포스 계정과 연동도 가능하다고 하고, 이번주 토요일에 경기가 있으니 한번 참여해보라는 뭐 그런 내용이었습니다. 그래서 한번 방문해 보았습니다.


https://csacademy.com/



사이트 디자인은 마치 안드로이드 폰 UI와 비슷한 형태였습니다. 깔끔하면서도 만든지 얼마 안 된 것 같은 그런 UI이지만 뭐 편리한 기능들은 꽤 많고 다 잘 작동했습니다. 생각보다 공부하기 좋은 기능들이 많이 있는데, 일단 제가 가장 좋아하는 1주일 정도마다 열리는 Round가 있고, 꽤나 자주 열리는 Hourly가 있습니다. 아직 Round를 한번 참여해본 것 말고는 사용을 해 보지 않아서 자세한 이야기는 못 드리겠네요.


콘테스트 외에 주제별로 풀어볼 수 있는 Problem set 기능도 제공합니다. Tasks라고 표현을 하는것 같습니다.


일단 코드포스 보다는 역사가 짧긴 한 것 같습니다. 코드포스가 Contest 번호가 400번대를 넘어섰는데, CS Academy는 58번째 Round를 진행하고 있네요.


Contest Round 외에도 Lesson이라고 해서 주제별로 Computer Science 관련된 자료구조나 알고리즘에 대한 공부 자료들이 있습니다. 그 외에도 그래프나 기하학적인 도형들을 그리는 툴도 있네요. 


그리고 특이했던 것 중 하나가 Contest Round 방식이었습니다. 코드포스와 비슷하게 Division을 1과 2로 나누어서 수준별 차이를 두고, Rating 시스템도 있습니다.


특히나 인상 깊었던 Contest Round 화면입니다. 온라인에서 실시간으로 코딩을 할 수 있고, 컴파일 및 실행과 제출을 한번에 할 수 있습니다. 매번 코드포스에서 문제를 풀 때에는 구름 IDE를 켜서 했던 것에 비해 비교적 간편했습니다.

언어도 다양하게 지원을 합니다. 문제들은 쓸데없는 문장 없이 간결했습니다.


또 특히나 좋았던 점은 아직 사용자가 많지 않아서 그런 것 일수도 있지만 서버 상태가 매우 쾌적했다는 것입니다. 랙이나 시간 지연없이 잘 동작했고, 문제 제출 시 몇번째 Test Case까지 맞았는지와 각각의 실행시간과 메모리 사용량을 알려줍니다.


그리고 콘테스트가 끝나면 Chatting 방에서 해당 라운드에 참여했던 사람들과 이야기를 할 수 있습니다. 그리고 약 15분만 기다리면 튜토리얼(문제에 대한 해설)과 Rating 변동 사항도 알려줍니다.


이번에 처음으로 한번 참여해 보았지만 편리하고 좋은 경험이었습니다. 앞으로도 CS Academy에서 계속 공부를 해 볼 생각입니다.


해당 플랫폼에 대한 더 정갈한 정리는 추후 제가 이 플랫폼을 많이 이용해본 뒤에 올리도록 하겠습니다.


때는 백준 1920번 문제를 풀 때 겪은 일이었습니다.

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


문제를 보자 마자 C++ STL에 있는 unordered_set을 이용하면 풀리겠거니, 하고 풀었더니 시간초과가 났습니다.


그래서 풀이를 찾아보니 바이너리 서치를 이용해서 풀더군요. 그래서 C++ STL Algorithm 헤더에 있는 binary_search를 이용해서 푸니 똑같이 시간초과가 났습니다.


예전에 C++ STL에 있는 upper_bound와 lower_bound가 O(lgN)이 아니라 선형 시간복잡도를 갖는다는 이야기를 들은적이 있습니다.(틀린 이야기라라고 합니다.) (binary_search는 lower_bound를 이용해서 구현된 것으로 알고 있습니다.) 그래서 vector container에 대한 binary_search를 커스텀으로 구현한 뒤 다시 풀어보니 또 시간초과...



그래서 binary_search를 잘못 구현한 것인가 싶어서 vector<int>::iterator를 이용하지 않고, int형 인덱스로 다시 구현해도 시간초과가 났습니다. 그래서 미뤄두고 있다가 최근 코드포스에서 비슷한 현상을 겪었죠.


http://codeforces.com/contest/892/problem/B




C++로 구현하니 시간초과가 나는데 요즘 공부하는 파이썬으로 짜니 오히려 정답처리가 되는... 그래서 대회가 끝나고 C++로 정답판정을 받은 사람들의 코드를 보니 다음과 같은 코드가 눈에 띄었습니다



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


cin, cout이 scanf, printf에 비해서 속도가 많이 느리다고 하더군요. std::endl보다 '\n'가 훨씬 빠르다는 이야기도 많이 들었지만, 실제 프로그래밍 문제를 풀 때 이러한 것 때문에 애로사항을 겪은적이 없었기 때문에 크게 신경쓰지는 않았었는데 이렇게 겪게 되었습니다.


따지고 보면 입출력 속도 때문에 시간초과가 난 문제 둘 다 최대 입력값 개수가 100만개 이상이었습니다.


찾아보니 여러가지가 자료들이 많았는데 결론적으로는 편리함 때문에 cin, cout을 쓰기 보다는 scanf와 printf를 사용하면 해결될 문제입니다. 그리고 좀 더 빠르게 하겠다면 글자 하나씩 입출력하는 함수들이 더 빠릅니다.(getchar, putchar 등등)


cin, cout을 사용하더라도 sync_with_stdio(false)로 속도를 가속할 수는 있지만, 이는 정공법적인게 아니라 일종의 편법같은 방식이고, 이 방식도 통하지 않는 경우가 있습니다.(그래도 scanf, printf속도로만 정답이 나오는 경우) 그리고 sync_with_stdio를 false로 준 경우, scanf, printf와 같은 C 표준 입출력 함수와 cout, cin같은 C++ 입출력 객체를 섞어 사용하는 경우 오답처리가 날 수 있습니다. 입출력이 코드 작성자가 의도하지 않은 순서로 나타난다던가 하는 일이 일어날 수 있다는 것이죠. 특히 멀티 쓰레드 환경일 경우 sync 값이 true일 때는 Thread safe라서 예상치 못한 값이 나오지 않지만, false를 시킬 경우 Thread unsafe해지기 때문에 예상치 못한 값이 나타날 수 있습니다.


그러므로 굳이 sync_with_stdio(false); 를 이용해서  C++ 입출력 객채를 가속시켜서 사용할 것이라면, scanf와 printf와 섞어서 사용하지 말 것이며, 싱글 쓰레드 환경에서만 사용(알고리즘 문제만 풀 때는 무조건 싱글스레드이므로 상관없지만 실무에선 쓰지말것)하고, 그래도 시간초과가 난다면 C 표준입출력 함수들을 사용하는 것을 추천하는 바입니다.


더 참고할 수 있는 자료들

알고스팟 - 언어별 input method 비교

https://algospot.com/forum/read/2496/

백준저지 -  1920번 문제 질문

https://www.acmicpc.net/board/view/9022

cpp reference - sync_with_stdio

http://en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio

stackoverflow - sync_with_stdio, cout.tie등에 대한 질문에 대한 답변

https://stackoverflow.com/questions/31162367/significance-of-ios-basesync-with-stdiofalse-cin-tienull

이번 코드포스 콘테스트는 Division 2만 개최되었다. Div1에 해당하는 사람도 참가는 가능하지만, competition은 Div2에 해당하는 사람만 이루어졌다.


풀지 못한 문제도 대회가 끝난 후 읽어보고 Editorial을 읽으면서 계속 공부하려고 해 보았는데, 오랜만에 제대로 공부하는 느낌이 드는 대회였다.


A번 문제

http://codeforces.com/contest/869/problem/A

하나하나 실제로 시뮬레이션 하면 된다. 이미 한번 나왔던 수 인지는 unordered_set으로 확인했다. 그런데 대회가 끝난 후 editorial을 읽어보니, 수학적 증명에 따라서 무조건 짝수개가 나온다고 한다. xor의 수학적 특징때문이다. A xor B = C라면 B xor C = A이라는 뭐 이런 특징때문이라고 한다. A번 문제 쉽다고 생각해서 그냥 풀어버리고 나왔는데, 생각보다 신박한 부분이 있다.

문제가 xi와 yi를 xor한 값이, 2n개의 배열, x1, x2, x3... xn, y1, y2, ... yn의 총 2n개의 배열 안에 들어있으면 카운트를 센다는 것인데, xor한 값이 2n보다 작은지라고 문제를 잘못 이해해서 hack 당한 사람들이 몇 명 있었다.

#include <iostream>
#include <unordered_set>
using namespace std;

int arr[2002][2];
unordered_set<int> s;
int main() {
	int n;
	cin >> n;
	for (int i=0;i < 2; i ++) {
		for (int j=0; j< n; j++) {
			cin >> arr[j][i];
			s.insert(arr[j][i]);
		}
	}
	
	bool even = true;
	for (int i=0; i < n; i++) {
		for (int j=0; j < n; j++) {
			auto& xi = arr[i][0];
			auto& yi = arr[j][1];
			int val = (xi ^ yi);
			if (s.find(val) != s.end()) {
				even = !even;
			}
		}
	}
	
	cout << (even ? "Karen" : "Koyomi") << endl;
}


B번 문제

http://codeforces.com/contest/869/problem/B

죄다 곱해버리면 될 것 같은데, 수가 커서 TLE가 나온다. 그런데 여기서 어차피 마지막 decimal digit을 구할 것이므로, 1의자리수만 고려하면 될 것 같다. 10번마다 주기적으로 회전하므로, 이를 고려하면 된다는 것! 그런데 또 보면 10번을 돈다는 것은, 0이 포함되므로 그냥 0이 나온다는 것이다. 따라서 a와 b의 차이값이 10이상이면 무조건 0이다.    

코드를 잘못 내서 hack 당했다.. 중간에 주석처리한 부분을 주석을 해제하면 Hack당한 코드가 된다. 주석 처리해서 지금은 Accept 판정을 받은 코드이다.

#include <iostream>

typedef long long ll;
using namespace std;

int main() {
	ll a, b, ans;
	cin >> a >> b;
	if (b-a >= 10) {
		cout << 0 << endl;
		return 0;
	}
	ans = 1;
	// b %= 10;
	// a %= 10;
	for (ll k = b; k > a; k--) {
		ans *= k;
		ans %= 10;
	}
	cout << ans << endl;
}


C번 문제

http://codeforces.com/contest/869/problem/C

섬 a,b,c에 대하여, a-b, b-c, c-a 연결 시 다리 개수는 모두 독립적이다. a-b 연결 다리 개수는 다리가 0개일때, 1개일때, ... n개일때 모두 고려해서 더하면 된다. n개는 min(a,b) 개이며, a와 b의 섬 개수 중 최소값이다. 다리가 i개 일때는 aCi * bCi * i!의 개수가 나오게 된다. 연결에 참여할 섬들을 고른 뒤 어떻게 연결할 것인지를 곱한 값이다. 팩토리얼과 이항계수는 dp로 구현했다. 메모리가 아슬아슬하다.

#include <bits/stdc++.h>

using namespace std;

#define MOD 998244353

typedef long long ll;

int dp[5001][5001];
int bicof[5001][5001];
int facto[5001];

ll get_facto(int n) {
	if (n <= 1) {
		return 1;
	}
	if (facto[n]) return facto[n];
	ll ret = 1;
	return facto[n] = (n * get_facto(n-1)) % MOD;
}

ll pascal(int n, int r) {
	if (n==r) return 1;
	if (n==0 || r==0) return 1;
	if (bicof[n][r]) return bicof[n][r];
	return bicof[n][r] = ((ll)pascal(n-1, r) + (ll)pascal(n-1, r-1)) % MOD;
}
ll get(int a, int b) {
	if (dp[a][b]) return dp[a][b];
	ll ret = 1;
	int limit = min(a, b);
	for (int i=1; i <= limit; i++) {
		ret += (((pascal(a, i) * pascal(b, i)) % MOD) * get_facto(i)) % MOD;
		ret %= MOD;
	}
	return dp[a][b] = ret;
}
int main() {
	int a, b, c;
	dp[1][1] = 2;
	cin >> a >> b >> c;
	ll ans = 1;
	ans *= get(a,b);
	ans %= MOD;
	ans *= get(b,c);
	ans %= MOD;
	ans *= get(c,a);
	ans %= MOD;
	cout << ans << endl;
}


D번 문제

http://codeforces.com/contest/869/problem/D

실제 대회당시 맞춘사람이 5명인가 밖에 안된다. 등록한사람이 7천명이 가까이되는데 말이다. 출제자가 D번문제와 E번 문제를 바꾸는게 나았을거라고 인정했다. 맞춘 사람 풀이를 보니, 실제로 가능한 경로를 모두 세되, 중복일 경우 최적화를 잘 적용한 것으로 보인다. 나중에 다시 도전해볼 예정이다.


E번 문제

http://codeforces.com/contest/869/problem/E

뭔가 풀 수 있을 것 같은데 못 풀 것 같은 문제이다. 2차원 세그먼트 트리나 쿼드 트리를 사용해야 한다고 한다. 세그먼트 트리와 쿼드 트리를 공부한 뒤 다시 도전할 예정이다.

블로그에 소스코드를 넣어야 하는 경우가 있습니다. 이러할 경우 코드 하이라이터를 사용해주면 좋은데, 그 중에서도 꽤나 나이스한 디자인을 보여주는 prismjs를 티스토리 블로그에 적용해보도록 하겠습니다.


prismjs 홈페이지 주소입니다.

http://prismjs.com/index.html


공식 홈페이지에 가서 DOWNLOAD라는 버튼을 누릅니다.



다운로드 페이지로 가면, 필요한 구성요소를 직접 골라서 다운로드를 받을 수 있습니다. Compresion Level에는 개발버전과 Minified 버전이 있는데, 개발 버전은 prism.js의 소스코드를 변경해서 자신의 입맛대로 만들어 쓸 경우 필요한 버전입니다. 저희는 그냥 있는 버전을 사용하기만 할 것이므로 Minified version을 선택합니다.


테마의 경우 오른쪽에 있는 원들을 눌러서 하단에서 실제 적용된 테마의 모습을 확인할 수 있습니다. 저 같은 경우에는 Okaidia 테마가 마음에 드므로 해당 테마를 선택했습니다.

그 외에도 하이라이팅을 지원하는 언어들과, 다양한 플러그인들을 제공합니다. 저는 기본 제공하는 언어 외에 C++ 언어를 추가하였고, 플러그인은 줄 번호를 표시해주는 플러그인을 선택했습니다.




하단으로 내려가면 적용될 테마의 모습이 보입니다. 다운로드 JS와 다운로드 CSS를 한번씩 눌러서 prism.js와 prism.css 파일을 다운로드 받습니다.



그리고 티스토리 관리 페이지로 가서 꾸미기 탭의 HTML/CSS 편집으로 들어갑니다.


우측 상단에 보이는 파일 업로드를 누릅니다.


여기에 추가 버튼을 눌러서 prism.js 파일과 prism.css 파일을 업로드 해 줍니다.


파일들이 추가된 모습들이 보입니다. 이 파일들이 추가된 경로를 확인해놓습니다. 저의 경우에는 images/prism.js와 images/script.js 의 경로에 추가되었습니다.


그리고 다시 HTML을 눌러서 태그를 추가해야 합니다.

head 닫는 태그, 즉 </head> 바로 위에 위와 같이 추가해줍니다.

<script src="./images/prism.js"></script>
<link rel="stylesheet" href="./images/prism.css">


그리고 저장 버튼을 눌러서 적용해 주면 됩니다.


이후 코드 하이라이팅이 필요한 경우 에디터에서 HTML 모드를 활성화 한 뒤 다음 태그를 입력해주면 됩니다.

<pre class="line-numbers language-cpp"> 
<code class="language-cpp">
//여기에 소스코드를 작성하시면 됩니다.
</code>
</pre>


HTML 모드에서 코드를 작성하려고 하면 <나 >와 같은 문자들을 또 수동으로 &gt; &lt; 등으로 이스케이프 처리해주어야 합니다. 따라서 추천하는 방법은 HTML모드에서 pre와 code 태그만 작성한 뒤, 위지윅 모드에서 소스코드를 붙여넣기하는 방법입니다.


WIn32 API란, 32비트 윈도우즈 운영체제 응용프로그램을 만들기 위한, 마이크로소프트에서 제공해주는 라이브러리 셋이라고 보시면 됩니다. 일반적으로 처음 프로그래밍을 접할 때 만들어보는 응용프로그램들은 까만 화면에 흰 글자로 이루어진 콘솔 어플리케이션이라고 불리는 CUI 앱입니다. 하지만 윈도우에서 동작하는 프로그램들은 대부분 GUI기반 앱들이죠. 이러한 윈도우즈에서 동작하는 GUI 앱의 첫 발걸음인 Hello World를 만들어 보겠습니다.


일단 비주얼 스튜디오 2017를 실행하도록 합니다.


그리고 파일 - 새로만들기 - 프로젝트를 누릅니다.

아래와 같은 창이 나타나게 되는데요, Windows 데스크톱 마법사를 누릅니다.


응용 프로그램 종류를 Windows 응용 프로그램으로 선택하고, 추가 옵션에 빈 프로젝트를 체크합니다.



프로젝트를 생성하고, 소스파일에 main.c혹은 main.cpp 파일을 하나 추가합니다.


그리고 소스코드에 다음 내용을 붙여넣습니다.



#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <tchar.h> 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
	MessageBox(NULL, _T("\tHello, World!"), _T("My First Win32 App"), NULL);
	return 0;
}


그리고 소스코드를 저장한 뒤, Ctrl + F5 키를 눌러서 빌드 및 실행을 해 봅니다.

다음과 같은 화면이 나타나면 성공!


이제 소스코드에 대한 간략한 설명을 해 보겠습니다.


첫번째 줄 #define WIN32_LEAN_AND_MEAN 이라는 구문은 불필요한 라이브러리들을 빌드에서 제외시키기 위한 내용이다. 빌드 시간을 줄일 수 있다. #include <windows.h> 를 선언하기 전에 define 해야 하며, 외부 MFC 헤더들을 포함시키지 않는다는 뜻입니다.


windows.h 는 메인 윈도우즈 헤더이며, Win32 API를 이용하여 앱을 작성할 시 필요합니다.

tchar.h 헤더는 _T(x)라는 매크로 함수를 사용하기 위해서 포함했다. _T(x)라는 매크로 함수는, 앱에서 유니코드 문자열 셋을 사용함에 따라 c언어에서 ascii 기반 char 배열형태의 문자열이 유니코드 기반 문자열과 호환되게 하는 매크로 함수이다. _T(x) 함수를 제거하고 프로그램을 실행할 시 에러메시지와 함께 컴파일이 안되는 모습을 확인할 수 있을 것입니다.


일반적인 콘솔 앱과는 달리 main 함수 대신 WinMain이라는 함수가 있다. 콘솔 앱에서 main함수와 같은 프로그램의 진입점(entry point)역할을 한다. WINAPI라고 되어 있는 부분은 해당 함수의 호출 규약(calling convention)을 규정해주는 구문이다. 호출 규약을 지정하지 않으면 C 호출 규약이 기본값으로 지정되게 된다. 윈도우즈 응용프로그램에서는 WINAPI 호출규약을 지정해야 합니다.


이제 WinMain 함수의 인자에 대해 알아보도록 합시다.

첫번째 인자 hInstance는 응용 프로그램의 인스턴스에 대한 핸들이다. 인스턴스란 실제 실행되어 메모리에 할당된 놈이라고 보면 된다. 실행되기 전 프로그램은 틀만 가지고 있을 뿐이고, 실행된 프로그램은 메모리를 할당받은 하나의 실체, 즉 인스턴스이다. 핸들이라고 하는 것은 해당 인스턴스에 개별적으로 부여된 아이디값 같은 것으로 보면 된다. 파일에 대한 핸들은 파일 디스크립터(File descriptor)라고 하듯이 윈도우 앱 프로세스에 대한 핸들은 hInstance 입니다.


두번째 인자인 hPrevInstance는 항상 NULL이다. 이 값은 Windows 3.1 시절에 사용되던 값으로, 가튼 앱의 다른 인스턴스가 이미 실행중이면 그 인스턴스의 핸들이 넘어 왔었습니다.


세번째 인자 IpCmdLine은 앱 실행 시 커맨드 라인 인자(Command Line Argument)를 담은 문자열 포인터이다. 예를들어 커맨드 라인에서 앱을 실행할 때 "HelloWorld.exe asdf -d 123" 이라는 명령어로 앱을 실행했다면, "asdf -d 123"이라는 문자열을 가리키게 됩니다.


제번째 인자인 nShowCmd는 앱이 실행된 후, 윈도우 상단 제목 줄에 나타날 앱의 제목을 결정합니다.



OpenGL을 사용한 예제 프로그램을 구동해보도록 하겠다. 일단 실행환경은 다음과 같다.


- Windows 10 64bit

- Microsoft Visual Studio 2017 Community

- GLUT


GLUT은 다음 링크에서 다운받을 수 있다.

https://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip


GLUT 라이브러리를 다운로드 받아서 압축을 풀면 다음과 같이 나타나게 된다.




예제들은 다음 링크에 있는 녀석들을 참조할 예정이다.

https://www.opengl.org/archives/resources/code/samples/glut_examples/examples/examples.html


일단 비주얼 스튜디오를 실행한다.






상단 메뉴에서 파일 - 새로 만들기 - 프로젝트 를 실행한다.

Win32 콘솔 응용프로그램이라는 항목이 있으면 그녀석을 선택하면 되는데, Windows 콘솔 응용프로그램이 있다. 

이 경우 좌측의 Windows 데스크톱을 눌러서 Windows 데스크톱 마법사를 통하여 프로젝트를 생성해주도록 한다.





Windows 데스크톱이라는 항목을 선택한 모습이다. 가장 아래에 Windows 데스크톱 마법사라는 항목이 나타나게 된다. 그냥 Windows 콘솔 응용 프로그램을 선택할 경우 '빈 프로젝트'라는 옵션이 나타나지 않게 된다.


Windows 데스크톱 프로젝트라는 추가 설정 창이 나타나게 되는데, 추가 옵션에 '빈 프로젝트'라는 항목에 체크를 해 주도록 한다. 그리고 프로젝트를 생성한 뒤, 프로젝트가 생성된 디렉토리로 이동하도록 한다. 기본 설정에 따라서  C:\Users\<유저명>\source\repos 라는 디렉토리에 Visual Studio 프로젝트가 생성되었다.





그리고 다운받은 GLUT에 들어있는 파일들을 아래와 같이 디렉토리를 만들어서 구성해주도록 한다. opengl_ex는 프로젝트를 생성해서 나타난 디렉토리이고, 같은 레벨에 3rd_party라는 디렉토리를 만든다.


그리고 3rd_party라는 디렉토리 하위에 GLUT이라는 디렉토리를 만든다.

그리고 GLUT이라는 디렉토리 하위에 GL이라는 디렉토리를 만들고, 같은 레벨에 glut.lib, glut32.lib 파일을 복사해서 집어넣어준다.

그리고 GL 디렉토리 안에는 glut.h 파일을 복사해서 집어넣어준다.


그리고 나서 Visual Studio에서 해당 외부 라이브러리 포함에 관련된 설정을 해 주어야 한다.





아래 그림에서 프로젝트 이름에 마우스 오른쪽 버튼을 눌러서 속성을 누른다.


그러면 아래와 같은 창이 뜨게 되는데, C/C++라는 필드가 보이지 않는 경우가 있다. 이러한 경우 소스코드를 하나 추가해주면 해당 필드가 나타나게 된다. 따라서 아래 창을 끄고 이전 화면으로 돌아간다.

소스파일이란 항목에 마우스 오른쪽 버튼을 클릭해서 추가 - 새 항목을 누른다.

C++ 파일을 선택하고 파일명에 main.cpp라고 작성한 뒤 추가를 누른다. 사실 구동해보려는 예제 코드가 c 소스코드이므로 main.c 라고 해도 무방하다.






openGL 예제코드가 있는 사이트에서 아무 코드나 고른다.

URL https://www.opengl.org/archives/resources/code/samples/glut_examples/examples/examples.html

선택한 소스코드를 Ctrl + A 키를 눌러서 모두 선택한 뒤 복사한다.


생성한 소스코드 파일에 고스란히 붙여넣기 한다.

그리고 다시 프로젝트에 마우스 오른쪽 버튼을 눌러서 속성 탭을 띄우면 C/C++라는 필드가 활성화 된 것을 볼 수 있다. C/C++ - 일반 탭에서 추가 포함 디렉터리 항목에 다음과 같이 입력한다.


../../3rd_party/GLUT/;

추가한 디렉토리 경로와 일치하는 것을 알 수 있다.

그리고 링커 - 일반 탭에서 추가 라이브러리 디렉터리에도 아래와 같이 입력한다.

../../3rd_party/GLUT/

링커 - 입력 탭에서 추가 종속성 탭의 오른쪽 끝에 있는 아래 꺽쇠를 누른다.


나타난 매뉴 중 <편집..> 을 누른다.



아래와 같이 3개의 항목을 추가해준다.

opengl32.lib

glu32.lib

glut32.lib


확인을 누르고 적용 버튼을 누른 뒤 변경사항을 저장한다.

그리고 main.c파일이 있는 곳에 dll파일들을 붙여넣기 해 준다. glut.dll 파일과 glut32.dll파일이 있다.




그리고 프로젝트 화면에서 Ctrl + F5를 누르면 정상적으로 실행되게 된다.




마이크로소프트사에서 개발한 대표적인 IDE인 비주얼 스튜디오(Microsoft Visual Studio)는 강력한 IDE입니다. 주로 C/C++언어 개발을 지원하지만, 최근에는 C#을 이용한 데스크탑 앱 등 다양한 언어와 어플리케이션을 지원합니다.


원래 수백만원대의 라이센스 비용을 지불해야지만 사용할 수 있는 IDE였으나, 마이크로소프트사에서 돈을 많이 벌어서 무료버전인 Community Edition을 제공합니다. 해당 IDE를 한번 설치해보도록 하겠습니다.


아래의 링크로 이동합니다.

https://www.visualstudio.com/ko/free-developer-offers/

우리가 설치할 것은 Visual Studio Community Edition이므로 가장 좌측에 보이는 '다운로드'를 클릭합니다. 그러면 잠시 뒤 아래와 같은 화면이 나타나면서 vs_Community 라는 파일이 다운로드되게 됩니다.

다운받은 파일을 실행하면 다음과 같은 화면이 나옵니다. '계속'을 눌러줍니다.


vs_Community 라는 파일은 PC에 비주얼 스튜디오를 설치하도록 하는 클라이언트 앱입니다. 대신 설치해주는 프로그램이라고 보시면 됩니다. 조금 기다리면 다음과 같은 화면이 나타나게 됩니다. 어떠한 용도로 Visual Studio 를 설치하느냐에 따라 선택사항이 달라질 수 있습니다.


저 같은 경우는 C++을 이용한 데스크탑 앱 개발 및 DirectX를 이용한 게임 개발이 목적이므로, 두개를 체크했습니다. 설치크기가 수백 MB에서 갑자기 5GB가량으로 올랐습니다. 용도를 선택하면 필요한 의존 라이브러리 등을 알아서 다 설치를 해 줍니다. 필요없는 것 까지 선택을 하면 용량을 많이 사용하고, 설치 시간도 많이 걸리게 됩니다. 필요최소한 내용을 선택해서 설치하시면 됩니다.

위와 같이 설치과정 화면이 나타나게 됩니다. 


완료되면 다음과 같은 화면이 나타나며 컴퓨터를 재시작하면 계속해서 설치가 이어지게 됩니다.




시작 메뉴에서 검색을 해서, Visual Studio를 실행합니다.



로그인을 하면 다양한 기능을 제공해준다고 하네요. 저는 일단 이 기능을 사용하지 않고 사용하도록 '나중에 로그인'을 눌렀습니다.


위와 같은 화면이 나타나는데요. 테마는 본인이 기호에 맞게 설정하시면 되고, 개발 설정은 개발하려는 앱의 형태에 따라서 고릅니다. 저는 C++ 어플리케이션을 개발할 것이므로, C++ 을 선택했습니다. 혹시 C언어로 개발하실 분도 C++를 선택하셔도 무방합니다.



Visual Studio가 실행된 모습입니다. 이제 마음껏 개발하시면 됩니다.

bits/stdc++.h 헤더 파일이란?

#include <bits/stdc++.h>

간혹 다른사람들이 C++을 이용하여 알고리즘 문제를 푸는 소스코드를 참조했을 때, 위와 같은 헤더가 나타나는 경우가 있습니다. 이 헤더는 어떤 것이고 어떠한 이유로 사용하는 것일까요?

 

bits/stdc++.h 헤더는 모든 표준 라이브러리가 포함된 헤더입니다. 프로그래밍 대회에서 위 해더를 사용하는 것은 좋은 아이디어 입니다. 문제를 풀 때 마다 #include <iostream> 등등을 작성하는 반복적인 일을 줄여서 시간안배를 도와줍니다. 특히나 문제 푸는 시간이 순위에 결정적인 경우에 더 도움이 될 수 있습니다. 프로그래밍 대회에서는 효율적이고 정확한 알고리즘을 찾는 것이 주가 되어야 하기 때문입니다.

 

하지만 소프트웨어 공학적인 측면에서는 #include 구문을 줄이는 것이 중요합니다. 많은 필요없는 파일들을 #include 하게 된다면, 컴파일 시간과 프로그램 크기가 쓸데없이 길어지고 커지게 됩니다.

 

다음은 bits/stdc++ 헤더의 단점들입니다.

- bits/stdc++.h 헤더는 GNU C++ 라이브러리의 표준 헤더가 아니기 때문에, GCC가 아닌 다른 컴파일러로 빌드를 하려고 한다면 실패합니다.

- 쓸대없는 파일들을 추가시켜서 컴파일 시간이 늘어납니다.

- 표준 C++이 아니기 때문에 이식성이 있지도 않고, 컴파일러 종속적입니다.

 

 

다음은 bits/stdc++ 헤더의 장점들입니다.

- 프로그래밍 대회에서 쓸데없는 시간낭비를 줄여주므로 사용하면 좋습니다.

- 필요한 헤더 파일 include 구문을 작성하는데 시간을 줄여줍니다.

- STL이나 GNU C++의 모든 함수들을 기억할 필요가 없습니다.

 

리눅스 머신에서 해당 헤더파일을 한번 열어봤습니다.

 

// C++ includes used for precompiling -*- C++ -*-

// Copyright (C) 2003-2015 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file stdc++.h
 *  This is an implementation file for a precompiled header.
 */

// 17.4.1.2 Headers

// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdalign>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif

// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>

#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif
 

헤더파일 길이는 100줄 남짓으로, 헤더치고는 별로 길지 않고, 거의다 쓸만한 헤더파일을 다 넣어버린 내용입니다.

 

 

 

윈도우즈 Visual Studio에서 bits/stdc++.h 헤더 사용하기

그런데 만약 이 헤더파일을 Windows Visual Studio에서 사용을 하고 싶다면 어떻게 하는 게 좋을까요?

 

일단 이 bits/stdc++.h 헤더파일은 비표준이기때문에 개발 등에서 사용하기엔 좋은 방법은 아닙니다.

 

하지만 알고리즘 문제해결 등을 할 것이라면, 일반적인 백준이나 코드포스와 같은 온라인 저지에서는 bits/stdc++.h 헤더를 다 지원하기 때문에, 윈도우에서 알고리즘 문제 풀이용으로 헤더를 사용해 보는 것은 나쁘지 않을 수 있습니다.

 

그러면 간단하게, 윈도우에서 적용되도록 비쥬얼 스튜디오 include 헤더들이 저장되는 디렉토리에 bits라는 폴더를 하나 만들고, 그 폴더 하위에 stdc++.h라는 이름의 파일을 집어넣으면 됩니다.

 

일단 윈도우즈 비쥬얼 스튜디오의 include 파일들이 저장되는 디렉토리를 찾아봅시다.

 

제 컴퓨터의 경우는 다음 경로가 include 디렉토리입니다.

 

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.12.25827\include\

 

물론 Visual Studio 버전과, 설치된 드라이브 명에 따라 조금씩 경로는 다를 수 있습니다.

 

이 경로에 bits라는 디렉토리를 하나 만들어 준 뒤, 그 하위 경로에 stdc++.h라는 텍스트 파일을 하나 만들어 줍시다.

 

(아마 해당 경로에는 바로 텍스트 파일을 만들기에는 관리자 권한이 필요할 수 있으므로, 바탕화면 등에 만든 뒤 드래그 앤 드롭으로 옮기는 식으로 하시는 편이 편합니다.)

 

즉 결과적으로 경로는

 

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.12.25827\include\bits\stdc++.h

 

가 되게 됩니다.

 

stdc++.h파일의 내용은 아래에 있습니다.

 

 

복사를 하시려면, 우측 하단의 view-raw를 누른 뒤 복사하시면 됩니다. 

 

 

 

 

한국정보올림피아드 2015년도 초등부 문제 풀이 포스팅입니다.

https://www.acmicpc.net/category/detail/1353


1번 사과문제입니다.

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

apple수를 사람수로 나누면 1인당 지급되는 사과수가 됩니다.

#include <iostream>

using namespace std;

int main() {
	int N;
	cin >> N;
	
	int ans = 0;
	while(N--) {
		int std, apple;
		cin >> std >> apple;
		int cnt = apple/std;
		int total = cnt * std;
		ans += apple - total;
	}
	cout << ans << endl;
}

2번 벨트문제입니다.

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

정수로 떨어지게 되어있으므로 그냥 계산하면 됩니다.

#include <iostream>

using namespace std;

int main() {
	int M;
	bool direction = false;
	int rot = 1;
	cin >> M;
	
	while (M--) {
		int a, b;
		int dir;
		cin >> a >> b >> dir;
		rot *= b;
		rot /= a;
		if (dir == 1) {
			direction = !direction;
		}
	}
	cout << (direction == true ? "1" : "0") << " " << rot << endl;
}

3번 카드문제입니다.

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

완전탐색을 하면 시간 초과가 난다. O(3^n)이 된다. 하지만 중복탐색되는 부분을 줄이면, 즉 Memoziation원리를 적용한 Dynamic programming으로 풀 시에는 나타나는 좀더 효율적으로 풀 수 있다. dp[왼쪽남은카드수][오른쪽남은카드수]로 한다면 최악의경우 O(n^2)이므로 2000^2 = 400만으로 1초안에 풀 수 있다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> L, R;
int n;

int dp[2001][2001];
bool chk[2001][2001];

int get(int l, int r) {
	if (l <= 0 || r <= 0) {
		return 0;
	}
	if (chk[l][r]) return dp[l][r];

	int ret;
	
	ret = max(get(l-1, r-1), get(l-1, r));
	int left_top_card_val = L[n-l];
	int right_top_card_val = R[n-r];
	if (left_top_card_val > right_top_card_val) {
		ret = max(ret, get(l, r-1) + right_top_card_val);
	}
	chk[l][r] = true;
	return dp[l][r] = ret;
}
int main() {
	cin >> n;
	L.reserve(n);
	R.reserve(n);

	for (int i=0; i < n; i++) {
		int tmp;
		cin >> tmp;
		L.push_back(tmp);
	}
	for (int i=0; i < n; i++) {
		int tmp;
		cin >> tmp;
		R.push_back(tmp);
	}
	cout << get(n, n) << endl;
}



4번 여왕별 문제입니다.

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

dfs로는 Time out이 납니다.. 그러므로 더 좋은 성능의 방법을 찾아봐야 합니다.

숫자가 감소하지 않는 방향이라고 했으니 규칙을 잘 보면, 왼쪽 끝과 위쪽 끝을 제외하고 내부쪽은 결과적으로 위쪽 값과 같은 값을 갖게 됩니다.

이러한 규칙을 이용하면 O(MN)으로 해결 가능합니다.

#include <iostream>
#include <vector>

using namespace std;

vector<int> border;

int main() {
	int M, N;
	cin >> M >> N;
	int len = M*2 - 1;
	border.resize(len, 1);
	while(N--) {
		int zero, one, two;
		cin >> zero >> one >> two;
		for (int i=zero; i < zero + one; i++) {
			border[i]++;
		}
		for (int i = zero+one; i < len; i++) {
			border[i] += 2;
		}
	}
	
	for (int i=0; i < M; i++) {
		for (int j=0; j < M; j++) {
			if (j==0) {
				cout << border[M-i-1] << ' ';
			} else {
				cout << border[M+j-1] << ' ';
			}
		}
		cout << endl;
	}
}


컴퓨터를 오래 사용하다가 보면, 컴퓨터가 많이 느려진다던지, 바이러스에 걸린다던지, 설정이 잘못되었다던지 등의 이유로 컴퓨터의 초기화가 필요할만한 상황이 있습니다. 이럴때 보통 사람들은 컴퓨터를 '포맷' 한다고 들 많이 표현을 합니다.


하지만 보통 이럴 때 사용하는 방법은 '포맷'이 아니라 '윈도우 재설치'라는 용어가 맞습니다. 간단하게 설명해서 '포맷'은 저장장치의 내용을 다 지워버리고, 새로 파일시스템을 구축하는 것이라고 보면 되고, '윈도우 재설치'는 컴퓨터의 시스템 관리 소프트웨어, 즉 운영체재를 지우고 새로 설치하는 것이라고 볼 수 있습니다.


그래서 단순히 컴퓨터가 이상해졌다고 하드디스크(혹은 SSD)를 '포맷'만 한다면 부팅이 되지 않는 그냥 고철덩어리 컴퓨터 하드웨어만 남게 되는 것이지요. 


어쨋든 용어는 바로 잡았으니, '포맷', 아니, '윈도우 재설치'를 하는 개괄적인 과정에 대해서 설명해 보도록 하겠습니다. 보통 주변의 컴퓨터를 잘 아는 사람에게 부탁하는 것이 일반적이기도 한데요, 전체적인 개념을 알고 인터넷을 조금 찾아보면 누구나 할 수 있는 과정이기도 합니다. 일단 필요한 것들은 다음과 같습니다.


1. 윈도우 라이센스 키

2. 윈도우 재설치를 할 노트북 혹은 데스크탑 컴퓨터

3. 내용이 다 지워져도 되는 8GB이상의 용량을 가진 USB 메모리 (혹은 윈도우 설치용 CD)

4. 그리고 부팅 USB를 만들때 쓸 컴퓨터


윈도우 버전에 따라서 용량이 다르기 때문에 USB 메모리가 꼭 8GB이상의 용량을 가질 필요는 없지만 안정적으로 하기 위해서는 8GB이상의 용량을 확보하는 것이 좋습니다.


컴퓨터에 관심이 크게 없으신 분들은 윈도우 라이센스에 대한 개념이 없으신 분도 있는데, 윈도우 운영체제는 10만원대 정도의 가격을 가진 '상용 제품'입니다. 즉, 돈을 받고 판매를 하는 하나의 상품이며, 정당한 대가를 지급하고 사용하는 것이 맞습니다. 그런데 보통 삼성, LG와 같은 곳에서 노트북을 사게 되면 윈도우가 기본적으로 설치되어 있는 경우가 많은데, 그런 경우는 노트북 가격에 윈도우 운영체제 가격이 포함되어 있는 것입니다. 그러한 노트북은 노트북에 붙어있는 스티커를 잘 찾아보면 윈도우 라이센스 키(시리얼 키)가 있을 것입니다. 이 키를 활용해서 윈도우 재설치를 할 수 있습니다. 혹은 이미 윈도우 운영체제를 사용하다가, Microsoft 계정으로 로그인 뒤 해당 윈도우즈 운영체제의 라이센스를 계정에다가 귀속시킨 경우, 해당 계정을 통하여 다시 라이센스를 복구할 수도 있는 것으로 알고 있습니다. 이에 대한 자세한 과정과 내용은, 다른 블로그나 Microsoft 공식 사이트, 도움말 등을 참고해 주시면 되겠습니다.


그러면 윈도우 재설치의 개괄적인 전체 흐름을 나열해보도록 하겠습니다.


1. 윈도우 라이센스 키 확보 (버전, 에디션 확인 필수!)

2. 해당 윈도우 버전에 맞는 ISO 파일 확보

3. ISO 파일을 이용하여 USB 메모리를 윈도우즈 부팅 USB로 제작

//혹은 2-3번 과정을 동시에 진행을 할, MediaCreationTool.exe를 이용하여 윈도우즈 부트 USB를 만들기

4. USB를 꽂은 상태에서 재설치 할 컴퓨터를 재부팅

5. 해당 컴퓨터의 BIOS 모드로 진입(혹은 UEFI 모드)후, 부팅 우선 순위(Boot Priority)를 변경하여 'USB 메모리'의 우선순위를 하드디스크나 SSD보다 높게 설정

6. USB로 부팅 시 윈도우 재설치 메뉴가 활성화됨. 절차에 따라서 재설치

7. 윈도우 재설치 이후 해당 하드웨어에 맞는 드라이버 파일 설치

8. 기타 필요한 한컴오피스나, MS 오피스 파일 등을 설치


전체적인 흐름은 다음과 같습니다. 2~3번 과정은 한번에 해결해주는 프로그램을 마이크로소프트에서 지원한다고 들은바가 있는 것도 같습니다. 각각의 과정에 대하여 상세하게 설명하면 하나하나 더 상세히 설명을 할 수 있지만, 그렇게 하게 되면 '간단 설명'이라는 이 포스팅의 성격과 달라지므로 이 포스팅은 여기서 끝마치겠습니다.

+ Recent posts