www.acmicpc.net/problem/10830

 

10830번: 행렬 제곱

크기가 N*N인 행렬 A가 주어진다. 이때, A의 B제곱을 구하는 프로그램을 작성하시오. 수가 매우 커질 수 있으니, A^B의 각 원소를 1,000으로 나눈 나머지를 출력한다.

www.acmicpc.net

 

 

 

[난이도] Gold4

[유형] Divide and Conquer(행렬곱)

 

[풀이]

1. 구조체 A를 정의하고 연산자 오버로딩을 이용해서 행렬곱 구현. 2. A^2n=A^n*A^n인 행렬의 성질을 이용하여 재귀함수로 정답 도출

#include <cstdio>
#include <vector>
using namespace std;
using ll = long long;
using vv = vector<vector<ll>>;
int N;
ll B,mod=1000;
struct A{
    vv arr;
    A(){};
    A(vv arr):arr(arr){};
    A operator*(A& a){
        vv tmp = arr;
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++){
                tmp[i][j]=0;
                for(int k=0;k<N;k++){
                    tmp[i][j] += arr[i][k]*a.arr[k][j];
                    tmp[i][j]%=mod;
                }
            }
        }
        return A(tmp);
    }
};
A base;
void print(A& a){
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            printf("%lld ",a.arr[i][j]);
        }
        puts("");
    }
}
A sol(ll n){
    if(n==1) return base;
    A u = sol(n/2);
    u=u*u;
    if(n%2) u=u*base;
    return u;
}
int main(){
    scanf("%d%lld",&N,&B);
    vv v;
    v.resize(N);
    for(int i=0;i<N;i++){
        ll t;
        for(int j=0;j<N;j++){
            scanf("%lld",&t);
            v[i].push_back(t%mod);
        }
    }
    base = A(v);
    A ret = sol(B);
    print(ret);
}

github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/10830.cpp

 

www.acmicpc.net/problem/1043

 

1043번: 거짓말

지민이는 파티에 가서 이야기 하는 것을 좋아한다. 파티에 갈 때마다, 지민이는 지민이가 가장 좋아하는 이야기를 한다. 지민이는 그 이야기를 말할 때, 있는 그대로 진실로 말하거나 엄청나게

www.acmicpc.net

 

 

[난이도] Gold4

[유형] DFS

 

[풀이]

지민이는 진실을 아는 사람이 있는 파티에서는 거짓말을 못한다. 어떤 파티에서 진실을 아는 사람이 있어서 진실을 말하면 그 파티에 참여한 진실을 모르는 사람이 참여한 모든 파티에서도 거짓말을 할 수 없다. 즉, 지민이가 진실을 말한 파티에 있는 모든 사람들은 진실을 아는거나 마찬가지이다. 이 성질을 이용하여 진실을 아는 사람들을 DFS를 이용하여 갱신해주면 답을 구할 수 있다.

 

#include <cstdio>
#include <vector>
using namespace std;
int N,M;
vector<int> pp[51],pty[51],tp;
bool visit[51];
void dfs(int n){
    visit[n] = 1;
    for(auto ptn : pp[n]){
        for(auto p : pty[ptn]){
            if(!visit[p]) dfs(p);
        }
    }
}
int main(){
    scanf("%d%d",&N,&M);
    int t,v;
    scanf("%d",&t);
    for(int i=0;i<t;i++) {
        scanf("%d",&v);
        tp.push_back(v);
    }
    for(int i=1;i<=M;i++){
        scanf("%d",&t);
        for(int j=0;j<t;j++){
            scanf("%d",&v);
            pty[i].push_back(v);
            pp[v].push_back(i);
        }
    }

    for(auto a : tp) dfs(a);
    int ans = 0;
    for(int i=1;i<=M;i++){
        bool ok = 1;
        for(auto p : pty[i]) {
            if(visit[p]){
                ok = 0;
                break;
            }
        }
        if(ok) ans++;
    }
    printf("%d",ans);
}

 

github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/1043.cpp

www.acmicpc.net/problem/1022

 

1022번: 소용돌이 예쁘게 출력하기

첫째 줄에 r1, c1, r2, c2가 주어진다. 모두 절댓값이 5000보다 작거나 같은 정수이고, r2-r1은 0보다 크거나 같고, 49보다 작거나 같으며, c2-c1은 0보다 크거나 같고, 4보다 작거나 같다.

www.acmicpc.net

 

[난이도] Gold4

[유형] 구현

 

[풀이]

소용돌이의 오른쪽 아래 꼭지점은 (2*n+1)^2 라는점을 이용

 

 

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int r1,r2,c1,c2;

int getV(int r,int c){

    int a = max(abs(r),abs(c));
    int v = (2*a+1);
    v*=v;
    if(a==r) return v-(a-c);
    v-=2*a;
    if(-a==c) return v-(a-r);
    v-=2*a;
    if(-a==r) return v-(a+c);
    v-=2*a;
    return v-(a+r);
}
int main(){
    scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
    int k = 0;
    for(int i=r1;i<=r2;i++){
        for(int j=c1;j<=c2;j++){
            int v = getV(i,j);
            k = max(v,k);
        }
    }

    int t = 0;
    while(k>0){
        t++;
        k/=10;
    }
    for(int i=r1;i<=r2;i++){
        for(int j=c1;j<=c2;j++){
            printf("%*d ",t,getV(i,j));
        }
        puts("");
    }
}

github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/1022.cpp

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

 

2624번: 동전 바꿔주기

명보네 동네 가게의 현금 출납기에는 k 가지 동전이 각각 n1, n2, … , nk개 씩 들어있다. 가게 주인은 명보에게 T원의 지폐를 동전으로 바꿔 주려고 한다. 이때, 동전 교환 방법은 여러 가지가 있을

www.acmicpc.net

 

[풀이] DP

 

dp 정의 : dp[n] = n원을 동전으로 교환하는 경우의 수.

 

 i : 0 ~ K-1까지 모든 동전 종류를 순회하면서

 i 번째 동전까지 썼을때의 dp[j] (j : T~1) 을 구해준다.

 

 T부터 거꾸로 하는 이유가 중요한데

1부터 할 경우 dp[1~j-1] 이 dp[j] 에 포함될 수 있기 때문이다.

dp[1~j-1]에는 i번째 동전을 쓰는 경우의 수까지 포함되어 있어서 dp[j]에는 포함되면 안된다.

       

동전 i를 몇개 선택할지 정해야 하기 때문에 동전 개수만큼 순회하면서 sum에 더해주고

if(j-sum >= 0 && dp[j-sum] > 0 을 만족하는 k를 찾으면 dp[j]에 dp[j-sum]을 더해주면 된다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <cstdio>
 
int T, K, P[1001], cnt[1001],dp[10001];
 
int main() {
    scanf("%d%d"&T, &K);
    for (int i = 0; i < K; i++scanf("%d%d"&P[i], &cnt[i]);
    dp[0= 1;
    for (int i = 0; i < K; i++) {
        for (int j = T; j >= 1; j--) {
            int sum = 0;
            for (int k = 0; k < cnt[i]; k++) {
                sum += P[i];
                if (j - sum >= 0 && dp[j-sum] > 0) dp[j] += dp[j - sum];
            }
        }
    }
    printf("%d",dp[T]);
cs

 

https://github.com/has2/Algorithm/blob/master/boj/RANDOM_PROBLEM/2624.cpp

https://leetcode.com/problems/battleships-in-a-board/

 

Battleships in a Board - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

[풀이] BFS

 

1XN 또는 NX1 모양의 배를 찾는 문제. 

문제의 조건에 배는 인접하지 않고

valid한 map만 주어진다고 했으므로

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
#include <vector>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
 
int N, M;
int dy[4= { 0,0,1,-1 };
int dx[4= { 1,-1,0,0 };
 
struct P {
    int y;
    int x;
    P(int y, int x) :y(y), x(x) {}
};
 
void bfs(int a, int b, vector<vector<char>>& board,vector<vector<bool>>& visit) {
 
    queue<P> q;
    q.push(P(a, b));
    visit[a][b] = 1;
 
    while (!q.empty()) {
 
        int cy = q.front().y;
        int cx = q.front().x;
        q.pop();
        for (int i = 0; i < 4; i++) {
            int ty = cy + dy[i];
            int tx = cx + dx[i];
            if (ty < 0 || tx < 0 || ty >= N || tx >= M || visit[ty][tx] || board[ty][tx] =='.'continue;
            q.push(P(ty, tx));
            visit[ty][tx] = 1;
        }
    }
 
}
 
class Solution {
public:
    int countBattleships(vector<vector<char>>& board) {
        int ans = 0;
        N = board.size();
        M = board[0].size();
        vector<vector<bool>> visit(N);
        for (int i = 0; i < N;i++) visit[i].resize(M);
 
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (board[i][j] == 'X' && !visit[i][j]) {
                    bfs(i, j, board, visit);
                    ans++;
                }
            }
        }
 
        return ans;
    }
};
cs

 

 

 

https://github.com/has2/Algorithm/blob/master/leetcode/419.%20Battleships%20in%20a%20Board.cpp

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

 

코딩테스트 연습 - 가장 큰 수

0 또는 양의 정수가 주어졌을 때, 정수를 이어 붙여 만들 수 있는 가장 큰 수를 알아내 주세요. 예를 들어, 주어진 정수가 [6, 10, 2]라면 [6102, 6210, 1062, 1026, 2610, 2106]를 만들 수 있고, 이중 가장 큰 ��

programmers.co.kr

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
 
bool cmp(const string& a, const string& b) {
    return a + b > b + a;
}
 
string solution(vector<int> numbers) {
    string answer = "";
 
    vector<string> ns;
    for (int n : numbers) ns.push_back(to_string(n));
    sort(ns.begin(), ns.end(), cmp);
    for (auto s : ns) answer += s;
    if (answer[0== '0') answer = "0";
    return answer;
}
cs

 

 

 

 

 

https://github.com/has2/Algorithm/blob/master/programmers/level2/%ED%81%B0%20%EC%88%98%20%EB%A7%8C%EB%93%A4%EA%B8%B0.cpp

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

 

코딩테스트 연습 - 큰 수 만들기

 

programmers.co.kr

[풀이] Greedy

 

Upperbound를 이용해서 고를 수 있는 범위 내에서 9~0까지 for문을 돌면서 가장 먼저 선택할 수 있는

값을 하나씩 고르면 된다.

 

 

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
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
 
string solution(string number, int k) {
    string answer = "";
    vector<int> a[10];
    for (int j = 0; j < number.size(); j++) {
        a[number[j] - '0'].push_back(j);
    }
    
    int cur = -1;
    for (int i = k; i < number.size(); i++) {
        for (int j = 9; j >= 0; j--) {
            if (a[j].empty()) continue;
            if (answer == "" && j == 0continue;
            auto ub = upper_bound(a[j].begin(), a[j].end(), cur);
            if (ub == a[j].end()) continue;
 
            int m = ub - a[j].begin();
            if (a[j][m] <= i) {
                answer.push_back(j + '0');
                cur = a[j][m];
                break;
            }
        }
    }
    return answer;
}
cs

 

https://github.com/has2/Algorithm/blob/master/programmers/level2/%ED%81%B0%20%EC%88%98%20%EB%A7%8C%EB%93%A4%EA%B8%B0.cpp

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

 

코딩테스트 연습 - 조이스틱

조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다. ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA 조이스틱을 각 방향으로 움직이면 아래와 같습니다. ▲ - 다

programmers.co.kr

[풀이] Greedy

 

가장 효율적으로 알파벳을 변경하는 방법은 이동시 가장 가까운 곳으로 이동해서 변경해주는 것이다.

어차피 변경해야할 모든 알파벳을 방문해야 하기 때문이다.

 

어떤 알파벳을 방문할 때 <-,->를 이용하는 두가지 방법 중 min값이 이동거리이다.

 

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
#include <string>
#include <vector>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int solution(string name) {
    int answer = 0;
 
    string curName(name.size(), 'A');
    int cur = 0;
 
    while (name != curName) {
 
        int near = -1;
        int minDiff = 30;
        for (int i = 0; i < name.size(); i++) {
            if (name[i] != curName[i]) {
                int diff = abs(cur - i);
                diff = min(diff, (int)name.size() - diff);
                if (minDiff > diff) {
                    near = i;
                    minDiff = diff;
                }
            }
        }
        cur = near;
        curName[cur] = name[cur];
        answer += minDiff;
        
        int k = name[cur] - 'A';
        answer += min(26 - k, k);
 
        //cout << "cur : " << cur << ", minDiff : " << minDiff << ", k : " << k << ", len -k : " << 26-k << endl;
    }
 
    return answer;
}
cs
https://github.com/has2/Algorithm/blob/master/programmers/level2/%EC%A1%B0%EC%9D%B4%EC%8A%A4%ED%8B%B1.cpp

+ Recent posts