uva : https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=13&page=show_problem&problem=1078

 

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

 

실수를 표현하는 방법 1)과 값을 최소화하기 위한 방식 2)을 알면 해결할 수 있는 문제입니다.

 

기본적으로 실수를 정수로 바꿔주는 캐스팅 과정에서

원하는대로 정확히 변경되지 않습니다.

 

double num 에 1.01을 입력받는 경우 디버깅으로 확인해보면 1.009999... 라는 값을 가지게 됩니다.

실수를 정수로 변환하는 과정에서 가장 간단한 방법은 0.5를 이용하는 것입니다.

 

이 문제는 계속 실수만 가지고 계산하다가는 정확한 값을 얻을 수 없을 것 같아서 아예 정수로 바꿔놓고 계산했습니다.

2번째 자리까지에 대한 값만 알면 되므로 정수 = 실수*100+0.5 로 캐스팅하여 이용했습니다.

 

풀이과정은 다음과 같습니다.

 

총 금액에 대한 평균을 구할 수 있고, 모든 사람은 최소한 평균이상의 금액은 지불해야 합니다.

이 때 총 금액을 인원수에 맞게 나누었을 때 나머지**)

"정확히 나눌 수 없으니 서로 1센트 정도는 더 내서 채워야되는 금액" 을 의미합니다.

 

그럼 필요한 정보들은 다음과 같아집니다.

1) 현재 사람들이 낸 금액

2) 현재 사람들이 내야할 금액

 

2) 현재 사람들이 내야할 금액은 기본적으로 총금액에 대한 평균값은 모두 가져야 할 것이고,

나머지**) 를 이용해서 2)의 값을 다시 계산해주면 됩니다.

 

결국 정답은 1) - 2) 또는 2) - 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
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <set>
#include <cmath>
#include <limits>
#include <cstring>
using namespace std;
 
int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
 
    int total;
    int person;
    double p;
    vector<int> pay, real_pay;
    cin >> person;
    while (person) {
        total = 0;
        for (int i = 0; i < person; i++) {
            cin >> p;
            pay.push_back(p * 100 + 0.5);
            total += pay[i];
        }
 
        int indivi = total / person;
        int mod = total % person;
        total = 0;
 
        sort(pay.begin(), pay.end(), greater<int>());
        for (int i = 0; i < person; i++) real_pay.push_back(indivi);
        for (int i = 0; i < mod; i++) real_pay[i]++;
        for (int i = 0; i < person; i++) total += abs(real_pay[i] - pay[i]);
        cout << fixed;
        cout.precision(2);
        cout << "$" << (total / 2/ 100.0 << "\n";
        cin >> person;
    }
 
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

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

uva 10150번 Doublets  (0) 2020.03.27
uva 10469번 To Carry or not to Carry  (0) 2020.03.23
uva 10010번 Where's Waldorf?  (0) 2020.03.23
uva 679 - Dropping Balls  (0) 2020.03.19
uva 100 - 3n+1 problem  (0) 2020.03.18

uva : https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&page=show_problem&problem=36

 

기본적인 dp문제, 재귀를 통하여 해결했습니다.

설명은 주석처리했습니다.

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
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <set>
#include <cmath>
#include <limits>
#include <cstring>
using namespace std;
 
typedef long long ll;
 
ll dp[1000001];
 
ll dfs(ll num) {
    if (num == 1return 1;
 
    if (num <= 1000000) {
        ll& res = dp[num];
        if (res) return res;
 
        ll ans = 0;
        if (num % 2) ans += dfs(num * 3 + 1+ 1;
        else ans += dfs(num / 2+ 1;
 
        return res = ans;
    }
    else {
        ll ans = 0;
        if (num % 2) ans += dfs(num * 3 + 1+ 1;
        else ans += dfs(num / 2+ 1;
        return ans;
    }
}
 
int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
 
    // 0 < n < 1000000 의 두 쌍 i, j가 주어지면
    // i부터 j까지의 모든 수 중 a가 1이 되기 위해 거쳐야하는 과정의 사이클 이 가장 많은 수를 출력한다.
 
    /*
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ..
    
    1 -> 1
    2 -> 2 1
    3 -> 3 10 5 16 8 4 2 1
    4 -> 4 2 1
    .. dp
    */
 
    // 100만까지는 무조건 1로 수렴가능하다고 했다
    // 만약 100만을 넘어서는 수가 있으면 memory로 해결할 수 없으니 직접 재귀를 돌린다.
 
    for (int i = 1; i < 1000001; i++)
        dp[i] = dfs(i);
 
    int i, j;
    while (1) {
        int a, b;
        cin >> i >> j;
        if (cin.eof()) break;
        a = i, b = j;
        if (i > j) swap(i, j);
        ll ans = 0;
        for (int k = i; k <= j; k++) ans = max(ans, dp[k]);
        cout << a << " " << b << " " << ans << "\n";
    }
 
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

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

uva 10150번 Doublets  (0) 2020.03.27
uva 10469번 To Carry or not to Carry  (0) 2020.03.23
uva 10010번 Where's Waldorf?  (0) 2020.03.23
uva 679 - Dropping Balls  (0) 2020.03.19
uva 10137 - the trip, BOJ 4411번  (0) 2020.03.19

비트마스킹의 개념을 알아두면 

값 하나에 여러가지 상태를 표시하는 기법을 알 수 있게 된다.

비트마스킹을 이용한 대표적인 문제가 외판원 순회(TSP) 인 것 같다.

 

예를 들어 집이 4개가 있고, 집 번호를 0~3, 이 집들을 방문한 정보들을 알고 싶다고 할 때,

우리는 비트마스킹 즉, 비트라는 값을 이용해서 하나의 값으로 여러 상태를 표현할 수 있다.

우선 집이 4개 => 4개의 집에 대한 정보를 표현하기 위한 크기가 필요하다.

이를 4비트(2^4 = 16(0~15))로 표현해보자

이 때, 4비트에 대한 비트 표현법은 1<<4 (2^4) 가 된다.

 

만약 0번 집만 방문했다면 0001 (실제로는 1이 저장된다)

만약 1번 집만 방문했다면 0010 (실제로는 2가 저장된다)

만약 1, 3번 집만 방문했다면 1010 (실제로는 2^1+2^3 => 10이 저장된다)

 

여기서 비트1은 방문을 했고 비트0은 방문을 하지 않았음을 나타낸다.

 

비트마스킹 정보를 배열에 저장한다고 가정하면 array[1<<4] 와 같이 선언하여 사용하면 된다.

 

----------- 연산 -------------

 

어떤식으로 사용되는지 알았다면, 이용할 수 있는 연산이 뭐가 있는지 알아보자

 

기본적인 비트연산은 알고 있을 것이다.

&연산의 의미는 두 비트값 모두 1이면 1, 아니면 0을 반환하고

| 연산의 의미는 둘중 한 값이라도 1이면 1, 아니면 0을 반환하고

~연산의 의미는 모든비트를 뒤집는 연산 0->1, 1->0 을 반환하게 된다.

 

비트의 크기는 N, 현재 비트값을 current 라고 할 때

 

. 모든 비트가 1인지 확인해보고 싶다 => current & (1<<N)-1 

 

. 모든 비트가 0인지 확인해보고 싶다 => current & 0

 

. K번째 비트가 1인지 0인지 확인해보고 싶다 => current & (1<<K)

K번째 비트만 둔채로 나머지 비트는 다 버려야 된다

이때 1<<K 의 의미는 K번째 비트만 1 처리하고 나머지 비트는 0 처리한다는 뜻이다.

(만약 K가 4라면 1<<4 => 16이 되고, 이를 비트로 나타내면 10000 (= 16) 가 된다는 뜻이다.

N이 4보다 큰 값이라고 할 때 좀더 정확히는 ...0000...0010000 이라는 의미가 된다)

 

. K번째 비트를 1로 만들고 싶다 => current | (1<<K)

위의 설명을 이해했다면 | (OR) 연산자를 사용해야 함을 알 수 있을 것이다.

K번째 비트를 1로 만들고 싶다면 K번째 비트를 1로 만들고 나머지 비트는 current 값 그대로 가져오면 된다.

 

. K번째 비트를 0으로 만들고 싶다 => current & ~(1<<K)

K번째 비트를 1로 만든 후, NOT연산 ~을 이용하여 뒤집어버리면

K번째 비트만 0이 되고 나머지는 1이 된다.

& 연산을 하면 K번째 비트는 강제로 0이 될 것이고, 나머지 비트들은 원래 값을 가지게 된다.

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

Point in a Polygon - 다각형 내부점 판단  (0) 2020.04.07
좌표 시계/반시계방향 정렬  (0) 2020.04.07
소인수분해  (0) 2020.02.28
기본 기하 공식  (0) 2020.02.28
볼록껍질 선분 처리하기  (0) 2020.02.28

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

 

BOJ 14499번 주사위 굴리기 문제입니다.

 

처음에 인풋이 세로N, 가로M, 주사위가 놓인 위치 x y, 명령갯수 K가 주어지게 되는데,

N, M, x, y, K 순서 그대로 주어지는 건줄 알고 풀었다가 틀렸네요

N, M, y, x, K 순서로 보셔도 되고

N, M, x, y, K 순서로 보는 대신, N은 x축, M은 y축 으로 보셔도 되는 문제입니다.

 

게시판에 분명 이의제기가 있을 것 같아서 찾아 읽어보니,

백준님께서 x축, y축에 대한 언급이 없다는 설명이 맞는 말씀 같습니다.

헷갈릴수는 있지만, 문제없는 인풋입니다.

 

주사위는 문제에 각 위치를 전개도로 주었기 때문에, 이를 이용해서 동서남북에 대한 위치변경을 코드해주시면 되고

문제에서 요구하는대로 코드해주시면 문제없이 통과됩니다

 

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
85
86
87
88
89
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <set>
#include <cmath>
#include <limits>
#include <cstring>
using namespace std;
 
struct direct {
    int y, x;
}direct[5];
 
int cube[7];
int arr[21][21];
int N, M, K;
queue<int> q;
 
void dfs(int y, int x, int cnt) {
    if (cnt == K) return;
 
    int yy, xx;
    int go;
    
    while (cnt<K) {
        cin >> go;
        cnt++;
        yy = y + direct[go].y;
        xx = x + direct[go].x;
        if (yy >= 0 && yy < N && xx >= 0 && xx < M) break;
        if (cnt == K) return;
    }
 
    if (go == 1) {
        int temp = cube[3];
        cube[3= cube[1];
        cube[1= cube[4];
        cube[4= cube[6];
        cube[6= temp;
    }
    if (go == 2) {
        int temp = cube[6];
        cube[6= cube[4];
        cube[4= cube[1];
        cube[1= cube[3];
        cube[3= temp;
    }
    if (go == 3) {
        int temp = cube[2];
        cube[2= cube[1];
        cube[1= cube[5];
        cube[5= cube[6];
        cube[6= temp;
    }
    if (go == 4) {
        int temp = cube[6];
        cube[6= cube[5];
        cube[5= cube[1];
        cube[1= cube[2];
        cube[2= temp;
    }
    if (arr[yy][xx] == 0) arr[yy][xx] = cube[6];
    else cube[6= arr[yy][xx], arr[yy][xx] = 0;
 
    cout << cube[1<< "\n";
    dfs(yy, xx, cnt);
}
 
int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
 
    direct[1= { 0,1 };
    direct[2= { 0,-1 };
    direct[3= { -1,0 };
    direct[4= { 1,0 };
 
    int y, x;
    cin >> N >> M >> y >> x >> K;
 
    for (int i = 0; i < N; i++)
        for (int j = 0; j < M; j++)
            cin >> arr[i][j];
 
    dfs(y, x, 0);
 
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

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

BOJ 1708번 볼록 껍질  (0) 2020.04.07
BOJ 1063번 킹  (0) 2020.04.07
BOJ 14503번 로봇 청소기  (0) 2020.03.13
BOJ 3709번 레이저빔은 어디로  (0) 2020.03.13
BOJ 1043번 거짓말  (0) 2020.03.13

+ Recent posts