백준: Class 5 - 9466, 10942(manachers 알고리즘), 11049

2 분 소요


</br> 클래스 5 계속
</br>

9466: 텀 프로젝트

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


    while( t-- ){
        int n;
        cin >> n;
        for(int i = 1; i <= n; i++){
            ind[i] = 0;
        }
        for(int i = 1; i <= n; i++){
            cin >> nums[i];
            ind[nums[i]]++;
        }
        int ans = 0;
        queue<int> q;
        for(int i = 1; i <= n; i++){
            if( ind[i] == 0 ){
                q.push(i);
                ans++;
            }
        }
        while( q.size() ){
            int now = q.front();
            q.pop();
            int nx = nums[now];
            ind[nx]--;
            if( ind[nx] == 0 ){
                q.push(nx);
                ans++;
            }
        }
        cout << ans << '\n';
    }

위상 정렬 문제다
연결된 게 하나 밖에 없어서 그냥 배열로 했다
ind 배열에 연결된 것들의 수를 저장한다. 만약 연결된 것들이 없으면 큐에 넣는다.
큐가 빌 때까지, 큐 안의 것과 연결된 애가 걔를 제외하고 연결된 것들이 없다면 얘도 큐에 넣어준다.

ex) 백준 예제
1
7
3 1 3 7 3 4 6


     1 2 3 4 5 6 7
ind: 1 0 3 1 0 1 1

queue <2, 5>
2에 연결된 1 -> ind가 0이 되므로 queue에 push
     1 2 3 4 5 6 7
ind: 0 0 3 1 0 1 1

queue <5, 1>
5에 연결된 3 -> ind가 2가 되므로 넘어감
     1 2 3 4 5 6 7
ind: 0 0 2 1 0 1 1

queue <1>
1에 연결된 3 -> ind가 1이 되므로 넘어감
     1 2 3 4 5 6 7
ind: 0 0 1 1 0 1 1
팀을 이룬 애들만 ind가 남음


</br>

10942: 팰린드롬?

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


int nums[4001];
int manachers[4001];

int func(int a, int b){
    int aa = 2*(a-1) + 1;
    int bb = 2*(b-1) + 1;
    int mid = (aa + bb) / 2;
    if( manachers[mid] >= (bb-aa)/2 ) return 1;
    return 0;
}

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

    int n;
    cin >> n;
    nums[0] = -1;
    int ind = 1;
    for(int i = 0; i < n; i++){
        cin >> nums[ind++];
        nums[ind++] = -1;
    }

    for(int i = 0; i < ind; i++){
        int cnt = 0;
        for(int j = 1; j < ind; j++){
            if( i-j < 0 || ind <= i+j || nums[i-j] != nums[i+j] ){
                break;
            }
            cnt++;
        }
        manachers[i] = cnt;
    }

    int t;
    cin >> t;
    while( t-- ){
        int a, b;
        cin >> a >> b;
        cout << func(a, b) << '\n';
    }
}

오늘 어쩌다 manachers 알고리즘을 봤었는데 어째 이 문제 보니까 바로 써먹게 생각나더라ㅋㅋ
간단하니 대충 설명하자면

s  = abcbdd
s' = 0a0b0c0b0d0d0

manachers[i] = i를 중심으로 반지름이 몇까지 갈 수 있는가?
ex) (0a0 - 010), (0a0b0a0 - 0103010), (0d0d0 - 01210)

따라서
s': 0a0b0c0b0d0d0
ma: 0101030101210

만약 1부터 5까지를 확인하라 하면, 그걸 manachers의 인덱스로 변환한다(2*(i-1) + 1).
따라서 (1, 9)의 중앙인 5의 가능한 반지름을 확인하면 된다.
manachers[5]가 (1, 9)의 반지름인 (9-1)/2 = 4보다 같거나 크다면 걔는 팰린드롬이겠지
</br>

11049: 행렬 곱셈 순서

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

int func(int a, int b){
    if( dp[a][b] != INT_MAX ) return dp[a][b];
    if( a == b ){
        dp[a][b] = 0;
        return 0;
    }
    if( b-a == 1 ){
        dp[a][b] = r[a] * c[a] * c[b];
        return dp[a][b];
    }
    for(int i = a; i < b; i++){
        dp[a][b] = min(dp[a][b], func(a, i) + func(i+1, b) + r[a]*c[i]*c[b]);
    }
    return dp[a][b];
}

재귀 dp로 풀었다
dp[시작][끝] = min(dp[시작][끝], dp[시작][중간점] + dp[중간점][끝] + 행렬 곱 연산 수)
</br>


열심히 합시다
</br>

댓글남기기