계단 오르기

문제번호 : 2579 번

문제링크 : https://www.acmicpc.net/problem/2579


문제

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다.

예를 들어 <그림 2>와 같이 시작점에서부터 첫 번째, 두 번째, 네 번째, 여섯 번째, 계단을 밟아 도착점에 도달하면 총 점수는 10 + 20 + 25 + 20 = 75점이 된다.

계단 오르는 데는 다음과 같은 규칙이 있다.

  1. 계단은 한 번에 한 계단씩 또는 두 계단씩 오를 수 있다. 즉, 한 계단을 밟으면서 이어서 다음 계단이나, 다음 다음 계단으로 오를 수 있다.

  2. 연속된 세 개의 계단을 모두 밟아서는 안된다. 단, 시작점은 계단에 포함되지 않는다.

  3. 마지막 도착 계단은 반드시 밟아야 한다.

따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세번째 계단을 연속해서 모두 밟을 수는 없다.

각 계단에 쓰여 있는 점수가 주어질 때 이 게임에서 얻을 수 있는 총 점수의 최대값을 구하는 프로그램을 작성하시오.

입력

입력의 첫째 줄에 계단의 개수가 주어진다.

둘째 줄부터 한 줄에 하나씩 제일 아래에 놓인 계단부터 순서대로 각 계단에 쓰여 있는 점수가 주어진다. 계단의 개수는 300이하의 자연수이고, 계단에 쓰여 있는 점수는 10,000이하의 자연수이다.

출력

첫째 줄에 계단 오르기 게임에서 얻을 수 있는 총 점수의 최대값을 출력한다.

예제

입력


6
10
20
15
25
10
20

출력


75

풀이

dp[i]는 이 게임에서 얻을 수 있는 계단 i개의 총 점수의 최대값 마지막 계단은 꼭 밟아야 하므로 마지막 계단을 밟는 방법에는 두가지 방법이 있다. 첫번째 방법은 마지막 계단의 바로 전 계단을 밟고 전전 계단은 안 밟은 경우고, 두번째 방법은 마지막계단의 전 계단을 건너뛰고 전전을 밟은 경우이다.

점화식으로 나타내면

  1. dp[n] = dp[n-3] + (data[n-1] + data[n])

  2. dp[n] = dp[n-2] + data[n]

이 두 경우의 최대값을 구해서 dp[n]값으로 정하면 된다.

코드

#include<iostream>

#include<cstring>

#include<algorithm>


int dp[301];

int main(){


int n, i,re=0;

scanf("%d", &n);

int* data = new int[n+1];

memset(data, 0, sizeof(data));

for (i = 1; i <= n; i++)

scanf("%d", data+i);


dp[1] = data[1];

dp[2] = data[1] + data[2];


for (i = 3; i <= n; i++){

dp[i] = max(data[i] + data[i - 1] + dp[i - 3] , data[i] + dp[i - 2]);

}


printf("%d", dp[n]);


} 


'Algorithm > 백준 BOJ' 카테고리의 다른 글

[2193] 이친수  (0) 2018.05.23
[2156] 포도주 시식  (0) 2018.05.23
[1260] DFS와 BFS  (0) 2018.05.11
[1966]프린터 큐  (0) 2018.05.11
[9012] 괄호  (0) 2018.05.01

DFS와 BFS

문제번호 : 1260 번

문제링크 : https://www.acmicpc.net/problem/1260


문제

그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.

입력

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 한 간선이 여러 번 주어질 수도 있는데, 간선이 하나만 있는 것으로 생각하면 된다. 입력으로 주어지는 간선은 양방향이다.

출력

첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.

예제

입력

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

출력


1 2 4 3
1 2 3 4

풀이

코드

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
#define IOFAST() ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;

vector <int> check;
//vector <int> check_b;
vector <vector<int>> a;
void dfs(int n){
check[n] = 1;
cout << n << " ";
for (int i = 0; i < (signed int)a[n].size(); i++){
int m = a[n][i];
if (check[m] == 0)
dfs(m);
}
}
void bfs(int n){
queue <int> q;
check[n] = 1;
q.push(n);
while (!q.empty()){
int m = q.front();
q.pop();
cout << m << " ";
for (int i = 0; i<(signed int)a[m].size(); i++){
int w = a[m][i];
if (check[w] == 0){
check[w] = 1;
q.push(w);
}
}

}

}

int main(){
IOFAST();
//bfs dfs
int i, v, e, n;
cin >> v >> e >> n;
check.resize(v + 1,0);
a.resize(v + 1);
for (i = 1; i <= e; i++){
int u, v;
cin >> u >> v;
a[u].push_back(v);
a[v].push_back(u);

}
for (i = 1; i <=v; i++){
sort(a[i].begin(), a[i].end());
}
dfs(n);
check.clear(); check.resize(v + 1);
cout << '\n';
bfs(n);

return 0;
}

'Algorithm > 백준 BOJ' 카테고리의 다른 글

[2156] 포도주 시식  (0) 2018.05.23
[2579] 계단오르기  (0) 2018.05.23
[1966]프린터 큐  (0) 2018.05.11
[9012] 괄호  (0) 2018.05.01
[1924] 2007년  (0) 2018.04.30

프린터 큐

문제번호 : 1966 번

문제링크 : https://www.acmicpc.net/problem/1966


문제

여러분도 알다시피 여러분의 프린터 기기는 여러분이 인쇄하고자 하는 문서를 인쇄 명령을 받은 ‘순서대로’, 즉 먼저 요청된 것을 먼저 인쇄한다. 여러 개의 문서가 쌓인다면 Queue 자료구조에 쌓여서 FIFO - First In First Out - 에 따라 인쇄가 되게 된다. 하지만 상근이는 새로운 프린터기 내부 소프트웨어를 개발하였는데, 이 프린터기는 다음과 같은 조건에 따라 인쇄를 하게 된다.

  1. 현재 Queue의 가장 앞에 있는 문서의 ‘중요도’를 확인한다.

  2. 나머지 문서들 중 현재 문서보다 중요도가 높은 문서가 하나라도 있다면, 이 문서를 인쇄하지 않고 Queue의 가장 뒤에 재배치 한다. 그렇지 않다면 바로 인쇄를 한다.

예를 들어 Queue에 4개의 문서(A B C D)가 있고, 중요도가 2 1 4 3 라면 C를 인쇄하고, 다음으로 D를 인쇄하고 A, B를 인쇄하게 된다.

여러분이 할 일은, 현재 Queue에 있는 문서의 수와 중요도가 주어졌을 때, 어떤 한 문서가 몇 번째로 인쇄되는지 알아내는 것이다. 예를 들어 위의 예에서 C문서는 1번째로, A문서는 3번째로 인쇄되게 된다.

입력

첫 줄에 test case의 수가 주어진다. 각 test case에 대해서 문서의 수 N(100이하)와 몇 번째로 인쇄되었는지 궁금한 문서가 현재 Queue의 어떤 위치에 있는지를 알려주는 M(0이상 N미만)이 주어진다. 다음줄에 N개 문서의 중요도가 주어지는데, 중요도는 적절한 범위의 int형으로 주어진다. 중요도가 같은 문서가 여러 개 있을 수도 있다. 위의 예는 N=4, M=0(A문서가 궁금하다면), 중요도는 2 1 4 3이 된다.

출력

각 test case에 대해 문서가 몇 번째로 인쇄되는지 출력한다.

예제

입력

3
1 0
5
4 2
1 2 3 4
6 0
1 1 9 1 1 1

출력


1
2
5

풀이

테스트케이스 개수를 입력받고, 그 수만큼 반복.

중요도와 찾고싶은 문서의 인덱스(0부터 시작)를 입력받는다(변수 n과 m )

중요도(imp)를 내림차순으로 넣기위해서 vector 를 만들고 (배열로 해도됨)

queue의 형을 pair형을 넣는다 그래서 pair의 first는 문서의 인덱스, second는 중요도 를 넣는다.
ex) 4 3 / 2 1 4 3

 vector 

 4

 3

2

 queue

 0 2

1 1 

2 4 

3 3 


그런다음,이중 반복문을 통해서 vector의 원소 순서대로, 즉 중요도가 큰 순서로 queue에서 그 값을 찾아 pop한다.pop할때는 pop된 문서의 수를 파악하기 위해서 cnt의 값을 +1 해주고,만약 pop하는 문서가 처음에 주어진 m문서라면 cnt값을 출력하고 모든반복문을 중단한다 (flag변수를 통해서)

코드

#include<iostream>
#include<vector>
#include<queue>
#include<utility> //pair
#include<algorithm> //sort
#define IOFAST() ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;

int main(){
IOFAST();

int i, testcase;
cin >> testcase;

for (i = 0; i < testcase; i++){
int j, k, n, m, imp, cnt = 0,flag=0;
queue <pair<int, int>> q;
vector<int> v;
cin >> n >> m; //문서의 수와 출력순서를 알고싶은 문서의 위치
for (j = 0; j < n; j++){
cin >> imp;
v.push_back(imp);
q.push(make_pair(j, imp));
}
sort(v.rbegin(), v.rend()); // 벡터를 거꾸로 정렬 (내림차순)

for (k = 0; k < v.size(); k++){
            if(flag==1) break;
for (j = 0; j < q.size(); j++){
if (v[k] == q.front().second){ //
cnt++;
if (m == q.front().first){
cout << cnt << '\n';
flag=1; //답을 찾았으니 첫번째 반복문을 끝내기 위해서
}
q.pop();
break;
}
else{ // 최대의 중요도가 아닐때 다시 큐에 삽입
int a, b;
a = q.front().first;
b = q.front().second;
q.pop();
q.push(make_pair(a, b));
}
}
}

}//testcase

return 0;

}

'Algorithm > 백준 BOJ' 카테고리의 다른 글

[2156] 포도주 시식  (0) 2018.05.23
[2579] 계단오르기  (0) 2018.05.23
[1260] DFS와 BFS  (0) 2018.05.11
[9012] 괄호  (0) 2018.05.01
[1924] 2007년  (0) 2018.04.30

큐 Queue

큐을 c로 구현하는 방법도 있지만 C++에서 제공하는STL을 통해 쉽게 사용 할 수 있다.

< 연산 >

  • push(x) : 큐의 맨 뒤에 데이터 x를 추가한다.

  • pop() : 큐의 맨 앞의 데이터를 삭제한다.

  • front() : 큐의 가장 앞의 데이터를 반환한다.

  • back() : 큐의 가장 뒤의 데이터를 반환한다.

  • empty() : 큐가 비어있는지 판단한다.(true or false)

  • size() : 큐의 사이즈를 반환한다.

예제

#include<iostream>

#include<queue>


using namespace std;


int main(){


queue<int> q; // 큐 생성


q.push(10); //데이터 삽입(뒤에)

q.push(20);

q.push(30);

q.push(40);

q.push(50);


while (!q.empty()){ // 스택이 비어있지 않다면


cout << "front data : " << q.front() << "  back data : " << q.back() << '\n';

cout << "queue size : " << q.size() << "\n\n";

cout << "data pop" << '\n';

q.pop(); //맨앞의 데이터 삭제

}

return 0;


}


'C++ > STL' 카테고리의 다른 글

C++ STL Stack 스택 기본과 예제  (0) 2018.04.30

인라인 함수

함수를 호출하면 스택메모리 사용이 증가하고 매개변수 때문에 메모리 복사가 일어난다.또 제어흐름도 이동해야 한다. 내부적으로 많은 연산들이 일어나는 것이다.

그래서 보통 이러한 함수 호출로 인한 오버헤드를 극복하고자 매크로를 사용한다.

특히 단순한 것임에도 불구하고 관리 상의 목적 때문에 함수로 만들어진 코드를 매크로로 변환할 경우 무시할 수없는 수준의 성능 향상을 기대해볼 수 있다.

하지만 본질적으로 매크로는 함수가 아니기때문에 매개변수형식을 지정할 수도 없고, 많은 논리적 오류를 발생시킬 수도 있다.



그래서 탄생한 것이 인라인 함수 이다 .

인라인 함수는 매크로의 장점과 함수의 장점을 두루 갖춘 함수이다.일반적인 함수 호출은 함수 주소로 갔다가 함수처리가 끝나면 다시 원래의 주소로 되돌아 오는 방식으로 시간이 오래걸린다.하지만 인라인 함수는 함수 호출없이 함수 코드를 함수호출 자리에서 처리하므로 함수를 수행하기 위해 함수가 있는 주소로 갔다가 되돌아 올 필요가 없어 속도면에서 유리하다.

문법도 간단하다. 함수 원형 앞에 inline 이라는 예약어만 붙이면 된다.

그렇다면 모든 함수가 인라인함수이면 더 좋지않을까? 라는 생각이 든다.

가능하다면 모두 인라인함수로 처리하면 좋겠지만 그렇지 않은 경우도 존재할것이다.

같은 코드가 기계어에서 계속 반복해서 나올 테니 코드의 길이가 일정 수준 이상 길어지면 인라인 함수가 되는 것은 바람직하지않다. 바람직한 코드 길이는 컴파일러가 정한다.

Visual Studio에서 솔루션탐색기 ->프로젝트이름 -> 속성 에서 구성속성 -> C/C++ -> 최적화를 누르면 [인라인 함수확장] 항목의 설정값이 기본값으로 지정되어있다. 이것은 Visual Studio에서는 컴파일 할경우 함수가 인라인함수로 선언되지 않거나, 인라인함수가 일반함수로 선언된경우 알아서 확장,축소해서 컴파일한다.

'C++' 카테고리의 다른 글

C++입출력 속도, 성능 개선  (0) 2018.04.30
C++, C와 무엇이 다를까  (0) 2018.04.30

+ Recent posts