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



로봇의 위치와 방향을 관리하며 bfs를 돌려주면 된다. 모든 순간에 로봇은 하나이기 때문에 큐에는 최대 하나의 좌표(로봇의 좌표)만 들어갈 수 있다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include<iostream>
#include<queue>
using namespace std;
typedef pair<intint> pii;
struct Robot {
    int r, c;
}bot;
int dir;
int row, col, m[51][51];
bool vis[51][51];
queue<Robot> q;
int dr[4= { -1010 };
int dc[4= { 010-1 };
int cnt = 1;
pii getBackPos(int r, int c, int dir) {
    if (dir == 0)
        return { r + 1, c };
    else if (dir == 1)
        return { r, c - 1 };
    else if (dir == 2)
        return { r - 1, c };
    else
        return { r, c + 1 };
}
void bfs(Robot bot) {
    q.push(bot);
    vis[bot.r][bot.c] = true// 로봇 시작 위치 청소
    while (!q.empty()) {
        Robot cur = q.front();
        q.pop();
        //int doneCnt = 0;
        bool goBack = true;
        for (int i = 0; i < 4; i++) {
            dir = (dir + 3) % 4;
            int nr = cur.r + dr[dir];
            int nc = cur.c + dc[dir];
            if (nr < 0 || nc < 0 || nr >= row || nc >= col || vis[nr][nc] !=0 || m[nr][nc] != 0) {
                //doneCnt++;
                continue;
            }
 
            else {
                //printf("%d, %d 방향 %d에서 %d, %d 방향 %d로 이동\n", cur.r, cur.c, cur.dir, nr, nc, (cur.dir+3)%4);
                q.push({ nr, nc });
                vis[nr][nc] = true;
                cnt++;
                goBack = false;
                break;
            }
        }
        //if (doneCnt == 4) {
        if(goBack){
            //dir = (dir + 1) % 4;
            //printf("%d %d 방향 %d 상태에서 후진시도\n", cur.r, cur.c, cur.dir);
            pii tmp = getBackPos(cur.r, cur.c, dir);
            if (tmp.first < 0 || tmp.second < 0 || tmp.first >= row || tmp.second >= col
                 || m[tmp.first][tmp.second] == 1)
                return;
 
            //후진 가능한경우
            else {
                q.push({ tmp.first, tmp.second});
                
            }
    
        }
    }
}
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> row >> col;
    cin >> bot.r >> bot.c >> dir;
    for (int i = 0; i < row; i++)
        for (int j = 0; j < col; j++)
            cin >> m[i][j];
    
    bfs(bot);
    
    cout << cnt;
    return 0;
}
 
cs


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


두가지를 생각해주면 된다.


1. + + - - * 이런 상황처럼 같은 연산자가 중복해서 들어가는 경우를 생각해서 연산자를 뽑아야한다.

순열로 뽑아야하므로 같은 것이 포함된 순열을 구현해주면 된다.


2. 연산자 우선순위가 없기 때문에, 단순히 숫자와 연산자를 분리해서 배열에 담은 뒤에, 하나씩 빼서 계산해주면 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<iostream>
#include<vector>
#include<set>
using namespace std;
 
vector<int> oprV; //뽑힐 수 있는 연산자들
vector<int> v; //뽑힌 연산자들 저장
set<vector<int> > st;
int n, num[12], oprCnt[4];
bool isused[12];
 
int calc(int a, int opr, int b) {
    if (opr == 0return a + b;
    else if (opr == 1return a - b;
    else if (opr == 2return a * b;
    else if (opr == 3return a / b; 
}
void func(int k) {
 
    if (k == n - 1) {
        st.insert(v); //set으로 중복 제거
        return;
    }
    
    for (int i = 0; i < n - 1; i++) {
        if (!isused[i]) {
            v[k] = oprV[i];
            isused[i] = true;
            func(k + 1);
            isused[i] = false;
        }
    }
}
int main(void) {
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> num[i];
 
    for (int i = 0; i < 4; i++) {
        cin >> oprCnt[i];
        while (oprCnt[i]--) { // + - * /    0 1 2 3 
            oprV.push_back(i);
            v.push_back(0);
        }
    }
 
    func(0);
 
    //중복 제거 하고 연산자 뽑은 결과
    int mx = -1111111111;
    int mn = 1111111111;
 
    for (set<vector<int> >::iterator itr = st.begin(); itr != st.end(); itr++) {
        vector<int> tmp = *itr;
        int res = num[0];
 
        for (int i = 0; i < tmp.size(); i++
            res = calc(res, tmp[i], num[i + 1]);
        
        if (res < mn) mn = res;
        if (res > mx) mx = res;
    }
    cout << mx << '\n' << mn << '\n';
    return 0;
}
cs


https://programmers.co.kr/learn/courses/30/lessons/17678


콘이 탈 수 있는 가장 늦은 셔틀버스를 타고 가려면, 몇시에 줄을 서야 하는지를 구하는 문제이다.


다음과 같은 방식으로 생각해 볼 수 있다.


기본적으로 가장 늦은 버스를 탄다는 것은, 막차를 탄다는 것이다. 따라서 막차에 자리가 있으면 그냥 막차를 타면 된다.


막차에 자리가 없는 경우를 생각해보면, 버스를 가장 늦은 시각에 탄 사람보다, 1분 더 빨리 나와서 버스를 타면 탈 수 있는 가장 마지막 순간에 버스를 타게 된다.


동일 시각이라도 콘은 가장 뒤에 줄을 선다고 했기 때문에, 1분 더 빨리 나와서 버스를 타면 되겠다.


위 두가지 경우로 구현을 해주면 되겠다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <string>
#include <vector>
#include<iostream>
#include<algorithm>
using namespace std;
 
struct Bus {
    int curPop, hour, mint; //버스 현재 인원, 출발 시, 출발 분
};
vector<Bus> bus;
 
string solution(int n, int t, int m, vector<string> timetable) {
    string answer = "";
    int hour = 9, minute = 0;
    for (int i = 0; i < n; i++) {
        bus.push_back({ 0, hour, minute });
        minute += t;
        if (minute >= 60) {
            hour++;
            minute -= 60;
        }
    }
    
    sort(timetable.begin(), timetable.end()); 
//일찍 온 사람부터 나오게 정렬(마지막에 탄사람이 제일 늦게 온 사람인데, 그 사람 찾으려고)
    
    int lastUp = 0// 마지막에 탄 사람의 인덱스
    for (int i = 0; i < timetable.size(); i++) {
        int hr = stoi(timetable[i].substr(02));
        int mn = stoi(timetable[i].substr(32));
        for (int j = 0; j < bus.size(); j++) {
            if (bus[j].curPop < m && (bus[j].hour > hr || (bus[j].hour == hr && bus[j].mint >= mn))) {
                bus[j].curPop++;
                lastUp = i;
                break//탈 버스가 정해졌으면 버스 검색 중지
            }
        }
    }
    string hrStr = "";
    string mnStr = "";
    if (bus[bus.size() - 1].curPop < m) { //막차에 자리가 남았다면 막차 시간에 오면 됨
         hrStr = to_string(bus[bus.size() - 1].hour);
         mnStr = to_string(bus[bus.size() - 1].mint);
 
    }
    else { //막차에 자리가 없으면, 마지막에 탄 사람보다 1분 일찍오면 무조건 탈 수 있음
        int lastHr = stoi(timetable[lastUp].substr(02));
        int lastMin = stoi(timetable[lastUp].substr(32));
        lastMin--;
        if (lastMin < 0) {
            lastHr--;
            lastMin += 60;
        }
         hrStr = to_string(lastHr);
         mnStr = to_string(lastMin);
    }
 
    if (hrStr.length() == 1) hrStr = '0' + hrStr;
    if (mnStr.length() == 1) mnStr = '0' + mnStr;
    answer = hrStr + ':' + mnStr;
    
    return answer;
}
cs


https://programmers.co.kr/learn/courses/30/lessons/17680


현재 캐시의 크기와, 사용 빈도에 관련된 정보를 배열을 활용해서 계속 검사해주며 miss와 hit 여부를 판단해주면 된다.


주의할 것은, 대소문자에 상관없이 비교를 하기 때문에 (Seoul과 seoul이 둘 다 입력으로 들어올 수 있는데, 같다고 판단해야 함) 이 부분을 잘 확인하면 된다.



어떤 문자열을 소문자로 변환하는 경우, algorithm 헤더에 있는 transform 함수를 이용한다.


파라미터는 transform(변환할 문자열의 시작주소, 변환할 문자열의 끝주소, 변환 결과를 저장할 문자열의 시작주소, ::변환방식)이다.


transform(ct[i].begin(), ct[i].end(), ct[i].begin(), ::tolower);


이런식으로 사용해준다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <string>
#include <vector>
#include<iostream>
#include<algorithm>
#include <string.h>
using namespace std;
int used[31], curSize = 0;
string cache[31];
int findCity(string city){
    for(int i = 0 ; i < curSize ; i++){
        if(cache[i] == city) return i;
    }
    return -1;
}
int solution(int sz, vector<string> ct) {
    int ans = 0;
    for(int i = 0 ; i < ct.size() ; i++){
        transform(ct[i].begin(), ct[i].end(), ct[i].begin(), ::tolower);
      
        int findIdx = findCity(ct[i]);
        if(findIdx >= 0){ //캐싱되어있는 경우
           ans++;
            for(int j = 0 ; j < curSize ; j++)
                used[j]++;
            used[findIdx] = 0;
        }
        else{
            //캐시 미스라서 추가해야 하는데 자리가 있는/없는 경우
            if(curSize < sz){ //자리 있
                cache[curSize] = ct[i];
                curSize++;
            }
            else// 자리 없
                int leastCnt = -1, idx = 0;
                for(int j = 0 ; j < curSize ; j++){
                    if(used[j] > leastCnt){
                        leastCnt = used[j];
                        idx = j;
                    }
                }
                cache[idx] = ct[i];
                 for(int j = 0 ; j < curSize ; j++){
                    if(j == idx) used[j] = 0;
                     else
                         used[j]++;
                }
            }
            ans += 5;
        }
    }
    return ans;
}
cs


https://programmers.co.kr/learn/courses/30/lessons/17682



문자열에서 숫자를 골라내야 하는데, 이 때 10이 포함된 경우를 잘 확인해주면 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <string>
#include<iostream>
#include<vector>
using namespace std;
 
bool isNum(char a) {
    return 0 <= a - '0' && a - '0' <= 10;
}
int solution(string dr) {
    vector<int> numV;
    vector<char> boV, opV(3'!');
 
    int ans = 0;
 
    string strNum = "";
    for (int i = 0; i < dr.length(); i++) {
 
        if (isNum(dr[i])) strNum += dr[i];
        else {
            if (strNum != "") {
                numV.push_back(stoi(strNum));
                strNum = "";
            }
            if (dr[i] == 'S' || dr[i] == 'D' || dr[i] == 'T')
                boV.push_back(dr[i]);
            else if (dr[i] == '*' || dr[i] == '#')
                opV[boV.size() - 1= dr[i];
 
        }
    }
 
    for (int i = 0; i < 3; i++) {
        if (boV[i] == 'D') numV[i] *= numV[i];
        else if (boV[i] == 'T') numV[i] = numV[i] * numV[i] * numV[i];
 
        if (opV[i] == '*') {
            if (i == 0)
                numV[i] *= 2;
            else {
                numV[i] *= 2;
                numV[i - 1*= 2;
            }
        }
        else if (opV[i] == '#')
            numV[i] *= -1;
    }
 
    for (int i = 0; i < numV.size(); i++)
        ans += numV[i];
 
    return ans;
}
cs


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

 

11328번: Strfry

문제 C 언어 프로그래밍에서 문자열(string)은 native한 자료형이 아니다. 사실, 문자열은 그저, 문자열의 끝을 표시하기 위한 말단의 NULL이 사용된, 문자들로 이루어진 문자열일 뿐이다. 하지만 프로그래밍 언어에서 문자열을 다루는 것은 매우 중요하기 때문에, C 표준 라이브러리는 문자열을 다루는 데에 매우 유용한 함수들을 제공하고 있다 : 그들 중에는 strcpy, strcmp, strtol, strtok, strlen, strcat 가 있다.

www.acmicpc.net

 

문자열을 무작위 재배열해서 반환하는 함수에 대한 문제이다.

두 문자열의 알파벳 성분이 일치하면 되기 때문에, 각 문자열을 이루는 알파벳의 개수를 파악해주면되겠다.

 

입력은 소문자로만 들어온다는 것을 확인하고, 각 문자열의 알파벳 개수를 파악해주자.

 

 

#include<string>
#include<iostream>
using namespace std;
int alpSrc[26], alpDes[26];
int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int tc;
	cin >> tc;
	string src, des;
	bool res = true;
	while (tc--) {
		
		cin >> src >> des;
		for (int i = 0; i < src.length(); i++) {
			alpSrc[src[i] - 'a']++;
			alpDes[des[i] - 'a']++;
		}
		res = true;
		for (int i = 0; i < 26; i++) {
			if (alpSrc[i] != alpDes[i]) {
				res = false;
				break;
			}
		}
		if (res)
			cout << "Possible" << '\n';
		else
			cout << "Impossible" << '\n';

		for (int i = 0; i < 26; i++) {
			alpSrc[i] = 0;
			alpDes[i] = 0;
		}
	}
	return 0;


문제 링크이다.

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

 

11722번: 가장 긴 감소하는 부분 수열

수열 A가 주어졌을 때, 가장 긴 감소하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 30, 10, 20, 20, 10} 인 경우에 가장 긴 감소하는 부분 수열은 A = {10, 30, 10, 20, 20, 10}  이고, 길이는 3이다.

www.acmicpc.net

 

풀면서 정답률이 이렇게 높게 나올 문제인가 하면서 자책했는데,

 

가장 긴 증가하는 부분 수열이라는 문제가 있어서 정답률이 상대적으로 높았던 것 같다.

 

 

(문제 풀이)

 

먼저 배열을 입력받고, 데이터들을 앞에 있는 모든 성분들과 비교해야 한다.

 

10 30 10 20 20 

 

위와 같이 배열이 주어졌다고 하면.

 

3번째 수인 10을 10과 30 모두와 비교하고, 20은 다시 처음부터 10, 30, 10 이런식으로 

 

이전에 나온 수들과 비교해야 한다.

 

즉 앞에서 해결한 문제가 뒤의 문제를 해결할 때 사용되기 때문에 dp라는 감을 잡고 접근하면 되겠다.

 

d[i]를 index i까지의 수를 활용해서 만들 수 있는 감소수열의 최대 길이라고 정한다.

 

확인하는 숫자가 이전 숫자보다 크다면 이전까지 나온 감소 수열의 길이에 영향을 미치지 않기 때문에 넘어가 주고, 

 

이전 숫자보다 작다면 처리를 해주면 된다.

 

길이의 최댓값을 찾고 있기 때문에, d[i]의 갱신도 최대 길이일때만 해주면 된다.

 

즉 위의 예시에서, 4번째 수인 20에 대한 처리를 한다고 해보자.

 

먼저 20은 10보다 크기 때문에 넘어간다.

 

이어서, 20은 30보다 작다 -> 30인 지점에서 감소 수열의 길이는 1이다. (엄밀히 말하면 0이라고 생각하지만 풀이의 간편성을 위해 1이라고 했다). 그렇다면 30까지의 수열과, 20이 연결되어서 수열의 길이는 1이 증가하게 되고, 수식으로 표현하면 d[20의 인덱스] = d[30의 인덱스] + 1 이다.

이것도 확정이 아니라, 만약 같은 방식으로 20보다 큰 30과 같은 수가 20의 이전에 여러개 나올 수 있는데,

d[20의 인덱스] = d[20보다 크고, 20보다 앞에 나온 수의 인덱스] + 1 이것들을 비교해서 최댓값을 d[20의 인덱스]로 결정해주면 된다.

 

#include<iostream>
using namespace std;
int d[1002];
int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);

	int n;
	cin >> n;
	int arr[1002];
	for (int i = 1; i <= n; i++) {
		cin >> arr[i];
	}

	for (int i = 1; i <= n; i++) {
		int Max = 0;
		for (int j = 0; j < i; j++) {
			if (arr[i] < arr[j]) {
				//작은 인덱스의 값보다 더 작은 값이 들어오면
				if (d[j] > Max) {
					Max = d[j];
				}
			}
		}
		d[i] = Max + 1;
	}
	
	int Max = 0;
	for (int i = 1; i <= n; i++) {
		if (Max < d[i]) {
			Max = d[i];
		}
	}
	cout << Max << '\n';
	
	return 0;
}

 

문제 링크는 다음과 같다.

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

 

13300번: 방 배정

표준 입력으로 다음 정보가 주어진다. 첫 번째 줄에는 수학여행에 참가하는 학생 수를 나타내는 정수 N(1 ≤ N ≤ 1,000)과 한 방에 배정할 수 있는 최대 인원 수 K(1 < K ≤ 1,000)가 공백으로 분리되어 주어진다. 다음 N 개의 각 줄에는 학생의 성별 S와 학년 Y(1 ≤ Y ≤ 6)가 공백으로 분리되어 주어진다. 성별 S는 0, 1중 하나로서 여학생인 경우에 0, 남학생인 경우에 1로 나타낸다. 

www.acmicpc.net

 

예시로 주어지는 학생 정보

 

위와 같은 예시를 보면, 쉽게 이차원 배열을 사용해야겠다는 생각을 떠올릴 수 있다.

 

특정 학년의 특정 성별을 가지는 학생의 수를 그대로 배열에 저장해준다.

 

k보다 인원이 작으면 방은 1개만 있으면 되고, 그 이상일 경우 k로 나눈 몫 + 1개만큼 방이 필요하다.

 

 

#include<iostream>
using namespace std;

int arr[2][7];

int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);

	int n, k;
	cin >> n >> k;

	int s, y;
	while (n--) { //n명의 정보를 2차원 배열에 저장
		cin >> s >> y;
		arr[s][y]++;
	}

	int room = 0;

	for (int i = 0; i < 2; i++) {
		for (int j = 1; j <= 6; j++) {
			if (!arr[i][j]) //특정 학년과 성별의 학생수가 0이면 continue
				continue;
			
			if (arr[i][j] < k) // k보다 작으므로 방은 하나만 있으면 됨
				room++;
			else { //k보다 크거나 같을 때
				if (arr[i][j] % k == 0) {
					//k로 나눠 떨어질 때
					room = room + arr[i][j] / k;
				}
				else {
					room = room + arr[i][j] / k + 1;
				}
			}
		}
	}

	cout << room << '\n';

	return 0;
}


문제링크

 

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

 

1919번: 애너그램 만들기

두 영어 단어가 철자의 순서를 뒤바꾸어 같아질 수 있을 때, 그러한 두 단어를 서로 애너그램 관계에 있다고 한다. 예를 들면 occurs 라는 영어 단어와 succor 는 서로 애너그램 관계에 있는데, occurs의 각 문자들의 순서를 잘 바꾸면 succor이 되기 때문이다. 한 편, dared와 bread는 서로 애너그램 관계에 있지 않다. 하지만 dared에서 맨 앞의 d를 제거하고, bread에서 제일 앞의 b를 제거하면, ared와 read라는 서

www.acmicpc.net

 

순서를 섞었을 때 문자열이 같아질 수 있느냐를 물어보는 문제였다.

 

단순히 문자열에서, 각 알파벳의 개수를 파악해주고 비교해주면 된다.

 

#include<iostream>
#include<string>
#include<math.h>
using namespace std;

int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);

	string org, cpr;
	int orga[26] = { 0, }, cpra[26] = { 0, };

	cin >> org >> cpr;

	for (int i = 0; i < org.length(); i++) {
		orga[org[i] - 'a']++;
	}
	for (int i = 0; i < cpr.length(); i++) {
		cpra[cpr[i] - 'a']++;
	}

	int cnt = 0;
	
	for (int i = 0; i < 26; i++) {
		cnt = cnt + abs(orga[i] - cpra[i]);
	}
	cout << cnt << '\n';

	return 0;
}
/*
strfry와 같은 원리. 단어에 쓰인 알파벳별 개수를 파악해서 비교.
입력 문자열의 길이가 다른 경우도 생각해줘야함
*/


문제링크

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

 

2577번: 숫자의 개수

첫째 줄에 A, 둘째 줄에 B, 셋째 줄에 C가 주어진다. A, B, C는 모두 100보다 같거나 크고, 1,000보다 작은 자연수이다.

www.acmicpc.net

 

설명은 코드의 주석으로 대체하겠다.

 

#include<iostream>
#include<string>
using namespace std;
int A, B, C, arr[10];
int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> A >> B >> C;
	long long res = A * B*C;	
	string str = to_string(res);
	for (int i = 0; i < str.length(); i++) {
		arr[str[i] - '0']++;
	}
	for (int i = 0; i < 10; i++) {
		cout << arr[i] << '\n';
	}
	return 0;
}
/*
각 자리수의 숫자를 확인하기 위해 계산 결과를 long long에서 string 으로 변환
string으로 변환된 값의 각 자리수인 char에서 int로 변환을 -'0'을 활용
*/


+ Recent posts