백준문제풀이

백준 문제 24440번 괄호 문자열 표기법 (Small) 문제풀이 c++

노가다 김씨 2022. 2. 8. 11:42

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

 

24440번: 괄호 문자열 표기법 (Small)

첫째 줄부터 각 테스트 케이스 별로 한 줄에 하나씩 N을 나타내는 가장 짧은 괄호 문자열을 출력한다. 단, 그러한 문자열이 여러 개 있으면 사전 순으로 가장 앞서는 것을 출력한다.

www.acmicpc.net

 

문제해석

 

이 문제는 dp문제이다.

dp[n]을 숫자 n을 나타내는 가장 짧고 사전 순으로 앞선 괄호 문자열로 정의를하자.

예를들어 n=25인경우를 살펴보면 

"("+dp[2]+dp[12]+")" , "("+dp[12]+dp[2]+")"

"("+dp[3]+dp[8]+")" , "("+dp[8]+dp[3]+")"

"("+dp[4]+dp[6]+")" , "("+dp[6]+dp[4]+")" 

dp[5]+dp[5]

(여기서 + 는 string concatenate를 의미)

총 7가지의 경우중 길이가 가장 짧은 것들중에서 사전식으로 가장 앞선것을 하나 고르면 된다.

다른 예시로 

n=100인 경우를 살펴보면

dp[2]+dp[50] , dp[50]+dp[2]

"("+dp[3]+dp[33]+")" , "("+dp[33]+dp[3]+")"

dp[4]+dp[25] , dp[25]+dp[4]

dp[5]+dp[20] , dp[20]+dp[5]

"(((("+dp[6]+dp[16]+"))))" , "(((("+dp[16]+dp[6]+"))))"

"(("+dp[7]+dp[14]+"))" , "(("+dp[14]+dp[7]+"))"

"(((("+dp[8]+dp[12]+"))))" , "(((("+dp[12]+dp[8]+"))))"

"("+dp[9]+dp[11]+")" , "("+dp[11]+dp[9]+")"

dp[10]+dp[10]

총 17가지중에서 조건에 맞는 하나가 답이 된다.

문제에서 n의값은 최대 10^6까지인데 사실상 2부터 root 10^6까지만 확인하면되므로 시간제한 내에 풀 수있다.

그렇게 생각하고 첫번째 답을 제출했으나 시간초과가 났다..

 

틀린 코드

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
string solve(int n);
string dp[1000001];
int main(){
    cout.tie(NULL);
    cin.tie(NULL);
    ios_base::sync_with_stdio(false);
    int n,t;
    cin>>t;
    while(t>0)
    {
        cin>>n;
        cout<<solve(n)<<"\n";
        t--;
    }
}
string solve(int n){
    dp[1]="";
    dp[2]="()";
    dp[3]="(())";
    string ans=dp[n];
    if(n<=3)
    {
        return ans;
    }
    if(!dp[n].empty())
    {
        return ans;
    }
    else
    {
        for(int j=2; j*j<=n; j++)
        {
            string s="";
            string p="";
            for(int k=0; k<n-(j*(n/j)); k++)
            {
                s=s+"(";
                p=p+"(";
            }
            string a=solve(j);
            string b=solve(n/j);
            s=s+a+b;
            p=p+b+a;
            for(int k=0; k<n-(j*(n/j)); k++)
            {
                s=s+")";
                p=p+")";
            }
            if(dp[n].empty())
            {
                dp[n]=min(s,p);
            }
            else
            {
                if(s.size()<dp[n].size())
                {
                    dp[n]=min(s,p);
                }
                else if(s.size()==dp[n].size())
                {
                    dp[n]=min({dp[n],s,p});
                }
            }
        }
        ans=dp[n];
        return ans;
    }
}

이렇게 제출했더니 시간초과가 나서 틀렸다.

왜 틀렸는지 몰라서 찾아봤는데 n-(j*(n/j))만큼 ( 문자와 ) 양끝에 붙이는것을 위에 코드처럼

for문을 통해 더했는데 이 방법이 시간을 엄청 잡아먹는다더라...

그래서 저렇게 하면 안되고 append 또는 push_back등 다른방법으로 ( 와 )를 양 끝에 붙이니까 통과했다.

 

정답코드

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
string solve(int n);
string dp[1000001];
int main(){
    cout.tie(NULL);
    cin.tie(NULL);
    ios_base::sync_with_stdio(false);
    dp[1]="";
    dp[2]="()";
    dp[3]="(())";
    int n,t;
    cin>>t;
    while(t>0)
    {
        cin>>n;
        cout<<solve(n)<<"\n";
        t--;
    }
}
string solve(int n){
    string ans=dp[n];
    if(!dp[n].empty())
    {
        return ans;
    }
    if(n<=3)
    {
        return ans;
    }
    else
    {
        for(int j=2; j*j<=n; j++)
        {
            string s="";
            string p="";
            s.append(n-(j*(n/j)),'(');
            p.append(n-(j*(n/j)),'(');
            string a=solve(j);
            string b=solve(n/j);
            s=s+a+b;
            p=p+b+a;
            s.append(n-(j*(n/j)),')');
            p.append(n-(j*(n/j)),')');
            if(dp[n].empty())
            {
                dp[n]=min(s,p);
            }
            else
            {
                if(s.size()<dp[n].size())
                {
                    dp[n]=min(s,p);
                }
                else if(s.size()==dp[n].size())
                {
                    dp[n]=min({dp[n],s,p});
                }
            }
        }
        ans=dp[n];
        return ans;
    }
}

난 append를 사용했지만 틀린코드에서 for문안을 s.push_back('(') s.push_back(')')이렇게 바꾸어도 아마 맞을 것이다.