BOJ : https://www.acmicpc.net/problem/1074

 

문제를 다시 풀어보았다.

분할정복, 말그대로 분할을 이용한 문제인 것 같다.

 

2*2 형태 부분만 찾으면 되기 때문에

분할은 다음과 같이 했다.

 

왼쪽상단을 fx, fy 라고하고 오른쪽하단을 ly, lx 라고가정

str 은 현재 왼쪽상단에 오게 될 숫자이고 num은 현재 오른쪽하단에 오게 될 숫자이다.

 

이때 4등분을 하게 되면 fx,fy,lx,ly 에 대한 위치를 분할해서 줄 수 잇을 것이며,

str, num 또한 위치에 맞게 분할해줄 수 있다.

2번이나 틀린 문제인데.. long long 을 사용하지 않아서 틀렸다.

2^15 의 좌표만 생각하고 int로만 했다가 WA을 받았다

숫자는 2^15 * 2^15 를 표현해야하니 longlong을 사용하자

 

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
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <set>
#include <cmath>
#include <limits>
using namespace std;
 
int N, r, c;
bool check;
 
void solve(int fy, int fx, int ly, int lx, long long str, long long num) {
    if (check) return;
    
    // 2*2 사이즈이면
    if (ly - fy == 1 && lx - fx == 1) {
        num--;
        if (fy == r && fx == c) cout << num - 3;
        if (fy == r && lx == c) cout << num - 2;
        if (ly == r && fx == c) cout << num - 1;
        if (ly == r && lx == c) cout << num;
        check = true;
        return;
    }
 
    // 범위를 n*n 기준 왼쪽위 1 오른쪽위2 왼쪽아래3 오른쪽아래4 로 가정하면
    // r c 의 위치를 보고 분할한다
 
    int midy = (fy + ly) / 2, midx = (fx + lx) / 2;
    long long div = (num-str) / 4;
    if (r <= midy && c <= midx) solve(fy, fx, midy, midx, str, num - (div * 3));
    if (r <= midy && c > midx) solve(fy, midx+1, midy, lx, str+div, num - (div * 2));
    if (r > midy && c <= midx) solve(midy + 1, fx, ly, midx, str+(div*2), num - div);
    else solve(midy+1, midx+1, ly, lx, str+(div*3), num);
}
 
int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
 
    cin >> N >> r >> c;
    r++, c++;
    int len = pow(2, N);
    solve(11, len, len, 0, len*len);
 
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

'algorithm > BOJ' 카테고리의 다른 글

BOJ 3709번 레이저빔은 어디로  (0) 2020.03.13
BOJ 1043번 거짓말  (0) 2020.03.13
BOJ 1026번 보물  (0) 2020.02.28
BOJ 2240번 자두나무  (0) 2020.02.26
BOJ 1504번 특정한 최단 경로  (0) 2020.02.24

소인수분해의 뜻은 임의의 수(소수 또는 합성수)를 소수의 곱으로 표현한 것을 말한다

 

예를 들어 28을 소인수분해하면 2*2*7 이 된다.

 

소인수분해나 소수를 관련하여 문제를 풀 때는

항상 N이라는 수를 p*q 로 나타낼 때

p가 sqrt(N)보다 크거나 같다면 q는 sqrt(N)보다 작거나 같다는 것을 이용해야 한다.

 

소인수분해를 가장 간단히 하는 방법은

N을 기준으로 2부터 sqrt(N)까지 가능한 수를 모두 나누어보는 것이고

이 때의 시간복잡도는 sqrt(N)이 된다

 

만약 폐구간[a,b] 에 대한 범위를 다루어야 한다면,

에라토스테네스의 체를 이용하여 좀 더 쉽게 해결할 수 있다.

에라토스테네스의 체를 구현하되, 소인수분해를 적용하려면 다음과 같다

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
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <set>
#include <cmath>
#include <limits>
using namespace std;
 
int factor[1001];
 
int solve(int n) {
    if (n <= 1return 1;
 
    cout << "현재 수는 " << factor[n] << " 입니다\n";
 
    return factor[n] * solve(n / factor[n]);
}
 
int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
 
    // 자기 자신을 소수로 둔다
    for (int i = 0; i < 1001; i++) factor[i] = i;
 
    for (int i = 2; i < sqrt(1001); i++) {
        // 만약 소수이면 (다른 수를 안만났으면)
        if (factor[i] == i) {
            for (int k = i * i; k < 1001; k += i) {
                // 초기화가 안됬을 때만
                if (factor[k] == k) factor[k] = i;
            }
        }
    }
 
    int n; cin >> n;
    cout << solve(n);
 
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

 

factor[i]의 의미는 "i라는 수를 만들기 위해 곱해야할 최소의 수" 를 뜻한다.

factor[2] 는 2가 될 것이고, factor[12] 역시 2가 될 것이고

2의 배수가 아닌 3의 배수만 생각해봐도 factor[9] 는 3이 됨을 뜻한다.

 

32줄의 조건문을 확인해주는 경우는

예를 들어 6을 생각했을 때

2가 먼저 factor[6] 에 담기게 된다.

그 후 3에 대한 반복문을 돌 때 factor[6]을 거치기 때문에 조건처리를 안해주면

factor[6] = 3 으로 수정되면서 6을 만들기 위한 최소곱의 값이 2가 아닌 3이 되기 때문이다.

 

위에서 28이라는 수를 소인수분해하면 2 2 7 이라고 말했었다.

코드가 제대로 구현되었는지 확인해보았다.

 

 

'algorithm > algorithm' 카테고리의 다른 글

좌표 시계/반시계방향 정렬  (0) 2020.04.07
bit masking (비트마스킹 정리)  (0) 2020.03.14
기본 기하 공식  (0) 2020.02.28
볼록껍질 선분 처리하기  (0) 2020.02.28
유클리드 호제법  (0) 2020.02.28

여기는 문제를 풀면서 기본으로 알고 있어야 하는 공식들을 정리한다.

 

-- 방정식

 

(중심이 (x.y)기준 (a.b) 이고 반지름이 r인 원의 방정식)

(x-a)^2 + (y-b)^2 = r^2

 

(기울기가 m이고 (x.y)기준 (a.b)를 지나가는 직선의 방정식)

y = m(x-a)+b

 

(두점 (x1.y1) (x2.y2) 를 지나가는 직선의 방정식)

y = ((y2-y1)/(x2-x1))*(x-x1) + y1

 

(2차 방정식 ax^2+bx+c = 0 의 근 x)

x = (B^2 (+-) sqrt(4*a*c)) / (2*a)

 

(3차 방정식 이상 => 미분을 통하여 기울기가 0이 되는 극점을 찾는 재귀를 반복)

 

(2개의 좌표를 기준으로 3등분하는 내분점 공식)

왼쪽좌표 : (x1,y1) => left // 오른쪽좌표 : (x2,y2) => right 로 생각할 때

3등분의 왼쪽좌표 : (left*2+right)/3

3등분의 오른쪽좌표 : (left+2*right)/3

 

 

세점이 주어졌을 때 삼각형의 넓이

 

 

'algorithm > algorithm' 카테고리의 다른 글

bit masking (비트마스킹 정리)  (0) 2020.03.14
소인수분해  (0) 2020.02.28
볼록껍질 선분 처리하기  (0) 2020.02.28
유클리드 호제법  (0) 2020.02.28
세그먼트 트리 정리  (0) 2020.02.05

기하 문제중 볼록껍질(convex hull) 을 다룰 때 좌표가 주어지면 

이를 선분으로 처리하는 방법을 정리해두자

 

보통 문제에서는 볼록껍질의 좌표를 시계방향/시계반대방향으로 주어진다.

 

볼록껍질에서 좌표가 주어지면 이를 선분처리해서 사용할 줄 알아야한다.

 

한 선분은 두 점으로 이루어져있으니 인접한 좌표를 기준으로 처리해야한다.

 

시계반대방향을 기준으로 정리해본다

 

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
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <set>
#include <cmath>
#include <limits>
using namespace std;
 
struct point {
    int x, y;
};
 
int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
 
    // 입력은 볼록껍질의 좌표를 시계 반대방향으로 주어진다고 가정
    // 볼록껍질을 윗껍질의 선분집합, 아랫껍질의 선분집합으로 나눈다.
    vector<pair<point, point> > upper, lower;
 
    // 입력받을 좌표의 갯수 n
    int n; cin >> n;
 
    // 볼록껍질의 좌표를 모아둘 벡터
    vector<point> v;
 
    // 좌표는 int형으로 받는다고 가정하고 x n개 y n개를 받는다
    for (int i = 0; i < n; i++) {
        point a;
        cin >> a.x >> a.y;
        v.push_back(a);
    }
 
    // 시계 반대방향은 인접한 좌표의 x를 기준으로 보았을 때
    // x가 증가하는 부분은 아랫껍질에 해당하고
    // x가 증가하는 부분은 윗껍질에 해당한다
 
    // 윗껍질, 아랫껍질 선분집합으로 나누기
    for (int i = 0; i < v.size(); i++) {
        if (v[i].x < v[(i + 1) % n].x) {
            lower.push_back({ v[i], v[(i + 1) % n] });
        }
        else if (v[i].x > v[(i + 1) % n].x) {
            upper.push_back({ v[i], v[(i + 1) % n] });
        }
    }
 
    // 윗껍질 선분과 아랫껍질 선분을 모두 출력해보면
    for (int i = 0; i < lower.size(); i++) {
        cout << "아랫껍질 선분 (" << lower[i].first.x << "," << lower[i].first.y << ") (" << lower[i].second.x << "," << lower[i].second.y << ")\n";
    }
    for (int i = 0; i < upper.size(); i++) {
        cout << "윗껍질 선분 (" << upper[i].first.x << "," << upper[i].first.y << ") (" << upper[i].second.x << "," << upper[i].second.y << ")\n";
    }
 
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

 

제대로 코드되었는지 확인해보았다.

 

 

 

 

 

'algorithm > algorithm' 카테고리의 다른 글

소인수분해  (0) 2020.02.28
기본 기하 공식  (0) 2020.02.28
유클리드 호제법  (0) 2020.02.28
세그먼트 트리 정리  (0) 2020.02.05
선분 교차 판별하기  (0) 2020.02.02

+ Recent posts