-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from Altu-Bitu/1012_extra
[투포인터] 10월 12일 -update
- Loading branch information
Showing
4 changed files
with
268 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// | ||
// Created by user on 2021-11-02. | ||
// | ||
|
||
#include <iostream> | ||
#include <algorithm> | ||
#include <vector> | ||
|
||
using namespace std; | ||
|
||
//좋은 수인지 검사하는 함수(투 포인터) | ||
bool isGood(vector<int> &num, int left, int right, int idx) { // n개 수가 저장된 정렬된 벡터, 왼쪽(벡터 시작점), 오른쪽(벡터 끝점), 현재 수 위치 | ||
while (left < right) { // 양 끝에서 차례로 계산하기 때문에 left가 right보다 작을 경우만 계산하면 된다. | ||
if (left == idx) { //left가 현재 수 위치와 같은 경우 | ||
left++; // left 위치 한칸 증가 | ||
continue; // 계속 | ||
} | ||
if (right == idx) { //right가 현재 수 위치와 같은 경우 | ||
right--; // right 위치 한칸 감소 | ||
continue; // 계속 | ||
} | ||
|
||
if (num[left] + num[right] == num[idx]) // left와 right위치에 있는 수의 합이 현재 수와 같다면 | ||
return true; // true 반환 | ||
|
||
if (num[left] + num[right] > num[idx]) //만드려는 수보다 크다면 | ||
right--; // 오른쪽 위치 감소 (이전 수가 무조건 더 작으니까(정렬되어있음)) | ||
else // 만드려는 수보다 작다면 | ||
left++; // 왼쪽 위치 증가 (다음 수가 무조건 더 크니까) | ||
} // end of while | ||
return false; // 조건 만족하지 않으면 false 리턴 | ||
} | ||
|
||
/** | ||
* 1. 각 수마다 양 쪽 끝에서 포인터를 시작해서 좁혀오면서 어떤 '다른 두 수'가 현재 수를 만들 수 있는지 검사 | ||
* 2. 포인터를 차례로 옮기며 검사하기 위해 미리 수를 오름차순 정렬함 | ||
* 3. 현재 만드려는 수의 위치와 left, right 포인터 위치가 겹칠 경우 처리 주의 | ||
*/ | ||
|
||
int main() { | ||
int n, ans = 0; | ||
|
||
//입력 | ||
cin >> n; | ||
vector<int> num(n, 0); // N개의 수 저장할 벡터 생성 | ||
for (int i = 0; i < n; i++) // 반복문 돌아가면서 | ||
cin >> num[i]; // n개의 수 입력받기 | ||
|
||
//연산 | ||
sort(num.begin(), num.end()); // 오름차순 정렬 | ||
for (int i = 0; i < n; i++) { // n번만큼 반복문 돌면서 | ||
if (isGood(num, 0, n - 1, i)) // 좋은 수라면 | ||
ans++; // 정답 추가 | ||
} | ||
|
||
//출력 | ||
cout << ans << '\n'; | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// | ||
// Created by user on 2021-11-02. | ||
// | ||
|
||
#include <iostream> | ||
#include <vector> | ||
|
||
using namespace std; | ||
|
||
int ans, n, m; | ||
vector<vector<int>> board; // 보드판 | ||
int dr[4] = {-1, 1, 0, 0}; // 상 하 | ||
int dc[4] = {0, 0, -1, 1}; // 좌 우 | ||
|
||
//board[row][col]을 가운데로 하는 +모양 만들기 | ||
int horn(int row, int col) { | ||
int cnt = 0, min_block = 1001, sum = board[row][col]; // 입력으로 최대가 될 수 있는 수: 1000 -> min_block에서는 최솟값 찾기 때문에 최대값으로 먼저 초기화 | ||
|
||
for (int i = 0; i < 4; i++) { // 상하좌우 방향 탐색 | ||
int nr = row + dr[i]; // 상 하로 이동하며 row 좌표 리셋 | ||
int nc = col + dc[i]; // 좌 우로 이동하며 col 좌표 리셋 | ||
|
||
if (nr < 0 || nr >= n || nc < 0 || nc >= m) //범위를 벗어나면 무시 | ||
continue; // 코드 진행 | ||
min_block = min(min_block, board[nr][nc]); //가장자리 블럭 중 값이 가장 작은 블럭 | ||
sum += board[nr][nc]; // 총합은 보드의 범위 내에 있는 좌표의 값 다 더한 것 | ||
cnt++; // 반복문 한 번 돌 때마다 cnt 증가 | ||
} | ||
|
||
if (cnt < 3) //가능한 가장자리가 최소 3개 이상이어야 함 | ||
return 0; // 함수 종료 | ||
if (cnt == 3) //ㅗㅏㅜㅓ | ||
return sum; // 보라색 조각 만들었으니 최종 전체합임. | ||
//+ | ||
return sum - min_block; // 전체 합에서 최솟값 빼면 최대값 | ||
} | ||
|
||
//한붓 그리기가 가능한 블럭들 백트래킹 탐색 | ||
void backtracking(int row, int col, int cnt, int sum) { | ||
if (cnt == 4) { //기저조건 : 4개의 블럭을 탐색함 | ||
ans = max(ans, sum); // 최대값 갱신 | ||
return; // 종료 | ||
} | ||
|
||
for (int i = 0; i < 4; i++) { // 상하좌우 방향 탐색 | ||
int nr = row + dr[i]; // row 좌표 갱신 | ||
int nc = col + dc[i]; // col 좌표 갱신 | ||
|
||
if (nr < 0 || nr >= n || nc < 0 || nc >= m || !board[nr][nc]) //범위를 벗어나거나, 이미 방문했다면 | ||
continue; // 무시 | ||
int save = board[nr][nc]; // 현재 블럭의 값 저장 | ||
board[nr][nc] = 0; // 방문했으니까 0으로 리셋 | ||
backtracking(nr, nc, cnt + 1, sum + save); // 갱신된 데이터로 재귀 | ||
board[nr][nc] = save; // backtracking 함수 구현 후 다음 탐색을 위해 0이었던 값에서 저장해 둔 원래 블럭의 값 돌려두기 | ||
} | ||
} | ||
|
||
/** | ||
* 1. 각 블럭을 백트래킹이 가능한 블럭과 불가능한 블럭으로 나누기 | ||
* -> 블럭을 한붓 그리기로 그릴 수 있으면 백트래킹이 가능 아니라면 불가능 | ||
* -> 보라색 블럭을 제외하면 모두 백트래킹 가능 | ||
* 2. 보라색 블럭은 + 모양에서 가장자리를 하나 제거한 것과 같음 | ||
* -> 가운데 블럭을 중심으로 가장자리 블럭을 붙여보고 가능한 최댓값 구하기 | ||
* 3. 각 블럭에 대해 깊이가 4인 백트래킹 함수를 수행하며 최댓값 갱신 | ||
* | ||
* 해설 : https://myunji.tistory.com/297 | ||
* *코드가 살짝 달라요(블로그 코드는 최적화 하기 전) | ||
*/ | ||
int main() { | ||
//입력 | ||
cin >> n >> m; | ||
board.assign(n, vector<int>(m, 0)); // 세로 n, 가로 m인 보드 세팅 | ||
for (int i = 0; i < n; i++) { // 세로 만큼 반복문 | ||
for (int j = 0; j < m; j++) // 가로만큼 반복문 돌면서 | ||
cin >> board[i][j]; // 칸에 쓰인 수 입력 | ||
} | ||
|
||
//연산 | ||
for (int i = 0; i < n; i++) { // 세로 크기만큼 | ||
for (int j = 0; j < m; j++) { // 가로 크기만큼 반복하면서 | ||
ans = max(ans, horn(i, j)); //보라색 블럭 처리 | ||
int save = board[i][j]; // 원래 블럭의 값 save에 저장 | ||
|
||
board[i][j] = 0; // 방문했으니 값 0으로 만들어준다 | ||
backtracking(i, j, 1, save); //나머지 모양 처리 | ||
board[i][j] = save; // backtracking 끝났으면 다시 원래 블럭의 값 저장 | ||
} | ||
} | ||
|
||
//출력 | ||
cout << ans; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// | ||
// Created by user on 2021-11-02. | ||
// | ||
|
||
#include <iostream> | ||
#include <vector> | ||
|
||
using namespace std; | ||
|
||
int chooseSushi(vector<int> &belt, int n, int d, int k, int c) { | ||
vector<int> sushi(d + 1, 0); // 초밥 가짓수보다 하나 더 많은 크기의 벡터 생성 | ||
|
||
//쿠폰으로 먹은 초밥 | ||
int section_sushi = 1; // 쿠폰으로 먹은 초밥 우선 더해두기 | ||
sushi[c]++; // 쿠폰으로 먹은 초밥 체크 | ||
|
||
//윈도우 초기화 | ||
for (int i = 0; i < k; i++) { // 연속해서 먹는 접시의 수만큼 반복하면서 | ||
sushi[belt[i]]++; // 나오는 스시들 체크 | ||
if (sushi[belt[i]] == 1) // 한 번 먹었다면 (전에 안나온 거니까) | ||
section_sushi++; // 그 종류로 먹는건 처음이니 증가 | ||
} | ||
|
||
int ans = section_sushi; // | ||
int left = 0, right = k - 1; // 윈도우 양 끝 초기값 설정 | ||
do { //원형태로 윈도우를 옮겨야 하기 때문에 종료조건은 left가 초기값(=0)이 됐을 때 | ||
sushi[belt[left]]--; // 윈도우 시작에 있는 초밥 종류를 먹은 값 감소했는데 | ||
if (!sushi[belt[left]]) // 0이면 윈도우에 이 초밥 종류가 없다는 의미니까 | ||
section_sushi--; // 먹은 종류감소 | ||
|
||
//윈도우의 양 끝 이동 | ||
left = (left + 1) % n; // n 넘어갈 수 있을 수 있으니 모듈러 연산 | ||
right = (right + 1) % n; | ||
|
||
sushi[belt[right]]++; // 윈도우 끝에 있는 초밥을 먹은 횟수를 증가했는데 | ||
if (sushi[belt[right]] == 1) // 새로 먹은 초밥 종류라면 | ||
section_sushi++; // 먹은 종류 증가 | ||
|
||
ans = max(ans, section_sushi); // 최대값으로 갱신 | ||
} while (left); // left가 0이면 종료 | ||
return ans; | ||
} | ||
|
||
/** | ||
* 1. 연속해서 먹어야 할 접시가 k로 고정됐기 때문에 슬라이딩 윈도우 | ||
* 2. 직선이 아니라 원 형태의 배열! 모듈러 연산을 통해 윈도우의 양 끝 위치 조절하기 | ||
* 3. 쿠폰으로 먹은 초밥을 먼저 고려해놓기 | ||
* 4. 초밥의 종류가 최대 3000개로 많지 않음. 보석 쇼핑 문제처럼 각 종류별 먹은 초밥의 개수를 세어주기 | ||
* | ||
* 그림 참고: https://cocoon1787.tistory.com/280 | ||
*/ | ||
int main() { | ||
int n, d, k, c; // n: 벨트에 놓인 접시 수, d: 초밥의 가짓수, k: 연속해서 먹는 접시의 수, c: 쿠폰 번호 | ||
|
||
//입력 | ||
cin >> n >> d >> k >> c; | ||
vector<int> belt(n, 0); // 길이가 n인 벡터 생성 | ||
for (int i = 0; i < n; i++) // n번만큼 반복하면서 | ||
cin >> belt[i]; // 각 벨트 위치의 회전초밥의 종류를 나타내는 정수 입력 | ||
|
||
//연산 & 출력 | ||
cout << chooseSushi(belt, n, d, k, c); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// | ||
// Created by user on 2021-11-02. | ||
// | ||
|
||
#include <iostream> | ||
#include <vector> | ||
|
||
using namespace std; | ||
const int SIZE = 26; // 알파벳 수 26개 | ||
|
||
//알파벳별 등장횟수 저장 | ||
vector<int> alphaMap(string str) { | ||
vector<int> result(SIZE, 0); // 알파벳 수 만큼의 크기의 벡터 생성 | ||
for (int i = 0; i < str.size(); i++) // 입력한 문자열의 길이만큼 반복문 돌면서 | ||
result[str[i] - 'A']++; // 알파벳 등장했다면 배열 수 추가해주기 | ||
return result; // 정답 반환 | ||
} | ||
|
||
/** | ||
* 단어가 같은 구성일 조건 | ||
* 1. 두 개의 단어가 같은 종류의 문자로 이루어짐 | ||
* 2. 같은 문자는 같은 개수만큼 있음 | ||
* | ||
* 비슷한 단어의 조건 | ||
* 1. 한 단어에서 한 문자를 더하거나, 빼면 같은 구성이 됨 | ||
* -> 두 단어에서 다른 문자의 개수가 총 1개 | ||
* 2. 한 단어에서 한 문자를 바꾸면 같은 구성이 됨 | ||
* -> 두 단어에서 다른 문자의 개수가 총 2개 | ||
* -> !주의! 이때, 두 단어의 길이가 같아야 함 cf) doll | do | ||
*/ | ||
int main() { | ||
int n, ans = 0; // n: 단어의 개수 | ||
string source, target; // source: 첫번째 단어 (비교군) | ||
|
||
//입력 | ||
cin >> n >> source; | ||
|
||
//연산 | ||
vector<int> source_alpha = alphaMap(source); // 첫번째 단어 알파벳 등장횟수 정리 | ||
while (--n) { // 첫 단어는 비교군으로 빠졌으니까 --n으로 (n - 1만큼 반복) | ||
cin >> target; // 비교할 단어 입력 | ||
|
||
int diff = 0; // 두 단어의 차이 계산 | ||
vector<int> target_alpha = alphaMap(target); // 비교할 단어 알파벳 등장횟수 | ||
for (int i = 0; i < SIZE; i++) //두 단어의 차이 | ||
diff += abs(source_alpha[i] - target_alpha[i]); // 알파벳별 등장횟수의 차의 합 | ||
if (diff <= 1 || (diff == 2 && source.size() == target.size())) //문자를 더하거나, 빼거나, 바꾸거나 | ||
ans++; // 정답 증가 | ||
} | ||
|
||
//출력 | ||
cout << ans; | ||
} |