백준: 20047

2 분 소요


</br> 계속 풀이
</br>

20047: 동전 옮기기

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

예선 당시 처음에 그리디로 생각해서 쭉 가다가 틀린 거 나오면 넣어 주고 하면 되지 않을까요?? 했는데 계속 틀렸다
반례가 있음…

ex) 
3
xox
xox
0 1
(답: YES)

그리디로 풀면
x, o
x
xox
처음 x가 맞아서 그냥 넘어가면 못 만들게 된다

그렇게 쉬우면 나올 리가 없겠지
그런데 I번도 나온 걸 보면 문제 난이도를 알 수가 없다는 게 또 그렇다

아무튼 요는 지금 둘이 똑같아도 동전을 한 번 넣어 봐 줘야 한다.

방법 1. 재귀

#include <bits/stdc++.h>

using namespace std;

string s1, s2;
char c[2];
int n;

bool func(int start, int skip){
    if( start + skip == n ) return true;
    if( s1[start] == s2[start+skip] )
        if( func(start+1, skip) ) return true;
    if( skip == 2 ) return false;
    if( c[skip] == s2[start+skip] )
        if( func(start, skip+1) ) return true;
    return false;
}

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

    string tmp;
    cin >> n >> tmp >> s2;
    int ind1, ind2;
    cin >> ind1 >> ind2;

    c[0] = tmp[ind1], c[1] = tmp[ind2];

    for(int i = 0; i < n; i++){
        if( i != ind1 && i != ind2 ) s1 += tmp[i];
    }

    if( func(0, 0) ) cout << "YES\n";
    else cout << "NO\n";

}

s1에서 동전 2개를 빼서 c[]에 저장한다
s2와 s1이 다르면 현재 넣을 수 있는 동전과 비교해 보고, 같다면 동전을 넣어 스킵할 수 있다.

</br>

방법 2. dp

#include <bits/stdc++.h>

using namespace std;

string s1, s2;
char c[2];
int n;
int dp[10001][3];

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

    string tmp;
    cin >> n >> tmp >> s2;
    int ind1, ind2;
    cin >> ind1 >> ind2;

    c[0] = tmp[ind1], c[1] = tmp[ind2];

    s1 += ' ';
    s2.insert(0, " ");
    for(int i = 0; i < n; i++){
        if( i != ind1 && i != ind2 ) s1 += tmp[i];
        dp[i][0] = 0;
        dp[i][1] = 0;
        dp[i][2] = 0;
    }

    dp[0][0] = 1;
    dp[0][1] = 0;
    dp[0][2] = 0;
    for(int i = 1; i <= n; i++){
        if( dp[i-1][0] ){
            if( s1[i] == s2[i] ) dp[i][0] = 1;
            if( c[0] == s2[i] ) dp[i][1] = 1;
        }
        if( dp[i-1][1] ){
            if( s1[i-1] == s2[i] ) dp[i][1] = 1;
            if( c[1] == s2[i] ) dp[i][2] = 1;
        }
        if( dp[i-1][2] ){
            if( s1[i-2] == s2[i] ) dp[i][2] = 1;
        }
    }

    if( dp[n][2] ) cout << "YES\n";
    else cout << "NO\n";

}

dp를 편하게 계산하려고 s1과 s2 앞에 공백을 하나 넣어 인덱스는 1부터하게 했다
dp[n][3]으로, 현재 동전 상태를 저장한다. 0은 넣은 동전 없음, 1은 왼쪽 동전 넣음, 2는 오른쪽 동전까지 다 넣음
이거는 s2 기준으로 인덱스를 해야 편하다
일단 dp[0][0]이 제일 처음 상태이므로 1로 하고, 나머지는 0으로 한다.
만약 dp[i-1][0]이 1이라면, 전 단계에서 동전을 하나도 안 쓴 게 가능하다는 말이다. 그 때 s1과 s2 비교 결과가 같으면 dp[i][0]도 1이다. 그리고 만약 왼쪽 동전과 s2가 같으면, 이 경우도 넣어주기 위해 dp[i][1]을 1로 한다.
dp[i-1][1]의 경우도 비슷하고, 만약 dp[i-1][2], 즉 동전을 다 쓴 경우라면 s1과 s2 비교 결과가 같을 때만 가능하다.
마지막엔 두 동전을 다 썼을 때만 가능하므로, dp[n][2]가 1인지 확인하면 된다.

인덱스가 헷갈려서 dp 풀이는 여러 번 틀렸다
</br>


1인분을 목표로
</br>

댓글남기기