백준: Silver2② - 1080, 1105, 1106

2 분 소요


</br> 실버 2 문제들 이어서
</br>

1080: 행렬

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

01 행렬을 3x3 씩 반전 시켜서 목표 행렬 만들기

    for(int i = 0; i < n; i++){
        string s;
        cin >> s;
        for(int j = 0; j < m; j++){
            a[i][j] = s[j] - '0';
        }
    }
    for(int i = 0; i < n; i++){
        string s;
        cin >> s;
        for(int j = 0; j < m; j++){
            if( s[j] - '0' != a[i][j] ) b[i][j] = 1;
        }
    }

    if( chkSame() ){
        cout << 0 << endl;
        return 0;
    }
    if( n < 3 || m < 3 ){
        cout << -1 << endl;
        return 0;
    }

    int ans = 0;

    for(int i = 0; i < n-2; i++){
        for(int j = 0; j < m-2; j++){
            if( b[i][j] ){
                change(i, j);
                ans++;
            }
            if( chkSame() ){
                cout << ans << endl;
                return 0;
            }
        }
    }

    cout << -1 << endl;

문제 조건이 좀 명확했으면!!
n, m이 3보다 작을 때도 뒤집을 수 있게 만들었더니 틀렸대서 뭔가 했는데 3x3 크기가 안 되면 못 뒤집게 한단다.

아무튼, a를 입력 받고 b에 b와 a의 차이를 저장한다. 그냥 그대로 입력 받고 a와 b를 비교해도 되지만 이게 보기도 더 편하게 보이고 코드도 간단해 지는 것 같아서…

ex)
// 입력
0000
0010
0000

1001
1011
1001

// 저장
1001
1001
1001

어차피 0과 1이기 때문에, 같은 곳이 2번 바뀌는 건 의미가 없다(최솟값을 구하므로).
따라서 처음부터 보면서 다른 게 있으면 3x3으로 뒤집어 주고, 다른 게 있을 때마다 그렇게 해 준다.
그리고 만약 행렬이 모두 0, 즉 다른 게 전혀 없으면 ans를 출력하고 종료하고,
for문이 끝나 버리면 답이 없다는 뜻이므로 -1을 출력하고 종료한다.
</br>

1105: 팔

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

수의 범위를 받고, 그 사이에 8을 가장 적게 포함한다면 그 때 8의 개수 구하기

    string l, r;
    cin >> l >> r;
    int cnt = 0;

    if( l == r ){
        for(int i = 0; i < l.size(); i++){
            if( l[i] == '8'){
                cnt++;
            }
        }
        cout << cnt << endl;
        return 0;
    }
    if( r.size() == l.size() ){
        int i = 0;
        for( ; i < l.size(); i++){
            if( l[i] == r[i] ){
                if( r[i] == '8' ) cnt++;
            }
            else{
                break;
            }
        }
        cout << cnt << endl;
    }
    else{
        cout << 0 << endl;
    }

갑자기 엄청 쉬운 문제다. 뭐지
8만 포함 안 하면 되기 때문에, 어쩔 수 없이 포함해야 하는 8만 세 주면 된다.
정수로서 계산할 필요가 없고, 자리수를 세는 게 편하기 때문에 string으로 받는다.

만약 l과 r이 같으면 가능한 수는 l(= r)밖에 없기 때문에 그냥 거기의 8의 수를 세 주고 끝낸다.

만약 둘의 사이즈가 같다면, 앞의 같은 부분은 어쩔 수 없이 포함해야 하는 부분이므로 거기서 8의 개수를 센다.
나머지 다른 부분 부터는 8의 개수를 셀 필요가 없으므로 바로 끝낸다.
ex) 981, 989 -> 98은 무조건 포함이므로 8 한 개.

만약 r의 자리수가 l보다 크면 무조건 8이 없는 수를 만들 수 있으므로 0을 출력하고 끝낸다.
</br>

1106: 호텔

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

적어도 c명의 손님을 가장 싼 비용으로 구하기

    for(int i = 1; i < c+1; i++){
        dp[i] = 10000000;
    }

    dp[0] = 0;
    for(int i = 1; i < c+1; i++){
        for(int j = 0; j < price.size(); j++){
            dp[i] = min(dp[i], dp[max(0, i-customers[j])] + price[j]);
        }
    }

    cout << dp[c] << endl;

그리디로는 안 풀리니 dp로 보면 되겠다
대충 dp[손님 수] = min(dp[손님 수 - i] + 비용[i])라고 식을 잡을 수 있다.
dp는 점화식만 알면 구현이 너무 쉬워서 좋아


</br>


3문제 씩 끊으니까 포스트 분량이 적당한 거 같다
</br>

댓글남기기