인프런 커뮤니티 질문&답변

요가인님의 프로필 이미지
요가인

작성한 질문수

10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트

3-E

3-E 질문있습니다!

작성

·

209

0

왜 메모리 초과가 나는지 잘 모르겠습니다 ㅠㅠ

http://boj.kr/3f4ea7f3a10b47edae0daa68dd2cf90d

그리고 선생님 코드와 무슨차이인지도 잘 모르겠습니다...

결국엔 6개의 경우의 수가 계속 추가 되는데

겹치는게 있을시 6개보다 적은 경우의 수가 들어간다

인데...

도저히 모르겠어요 ㅠㅠㅠ

#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
using namespace std;

int N, ret;
vector<int> scv;
queue<pair<vector<int>, int>> q;
set<vector<int>> visited;


vector<int> Damage(vector<int> v)
{
	int divide = 1;
	for (int i = 0; i < v.size(); i++)
	{
		v[i] -= 9 / divide;
		divide *= 3;
	}

	return v;
}

void Mutalisk()
{
	while (q.size())
	{
		vector<int> v = q.front().first;
		int cnt = q.front().second;
		q.pop();

		v = Damage(v);
		sort(v.begin(), v.end(), greater<int>());
		for (int i = (int)v.size() - 1; i >= 0; i--)
			if (v[i] <= 0)
				v.pop_back();

		if (v.size() == 0)
		{
			ret = cnt + 1;
			return;
		}

		do
		{
			q.push({ v, cnt + 1 });
			auto it = visited.insert(v);
			if (it.second == false)
				continue;
		} 
		while (prev_permutation(v.begin(), v.end()));
	}
}

int main()
{
	cin >> N;
	for (int i = 0; i < N; i++)
	{
		scv.push_back(0);
		cin >> scv[i];
	}

	sort(scv.begin(), scv.end(), greater<int>());

	do 
	{
		q.push({ scv, 0 });
	}
	while (prev_permutation(scv.begin(),scv.end()));

	Mutalisk();

	cout << ret;

	return 0;
}

답변 1

0

큰돌님의 프로필 이미지
큰돌
지식공유자

안녕하세요 가인님 ㅎㅎ

일단 이코드는 고쳐야할 점들이 몇가지 있습니다.

순열: SCV의 상태 - 순열을 생성하기 위해 prev_permutation을 사용하는 것은 조금은 비효율적입니다.

데미지 계산: pop_back() 등을 기반으로 하는데.. 너무 복잡합니다.

 

대표적으로 이부분이 문제인데요.

		do
		{ 
			q.push({ v, cnt + 1 });
			auto it = visited.insert(v);
			if (it.second == false)
				continue;
		} 
		while (prev_permutation(v.begin(), v.end()));
  1. 일단 이 코드는 continue를 해도 무조건 permutation이 잡히게 됩니다. 즉, 매번 v.size()!의 순열이 동작하게 되는 것이기 때문에 조금은 비효율적이라고 볼 수 있습니다.

  2. 대미지를 고정시키고 scv를 순회하는 것은 좋은 생각입니다만.. 이부분에 대한 로직이 좀 이상합니다.

     

     

    대미지를 준 상태 -> 해당 정점 방문했는지 체크하는 식으로 해야 하는데 이로직 기반으로는 그게 어렵습니다. 만약 그렇게 하더라도 좀 복잡해지는게

대미지를 주고 원복해야 하는데 해당 부분에 있어서 그냥 -가 아니라 max를 기반으로 했기 때문에 이렇게 코드를 짠다고 해도 해당 부분에 대한 로직의 수정이 필요합니다.

 

일단은 제가 이렇게 다듬어봤는데요. 참고 부탁드립니다. (답은 아닙니다. )

#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
using namespace std;

int N, ret;
vector<int> scv;
queue<pair<vector<int>, int>> q;
set<vector<int>> visited;
bool check(vector<int> v){
    for(int i : v){
        if(i != 0) return false; 
    }
    return true;
}
void Mutalisk()
{
    visited.insert(scv);
    q.push({scv, 1});
    while (q.size())
    {
        vector<int> v = q.front().first; 
        int cnt = q.front().second; 
        q.pop(); 
        if(check(v)){
            ret = cnt; 
            break;
        }     
        sort(v.begin(), v.end());
        do
        {  
            int j = 0; 
            for(int i : {9, 3, 1}){
                v[j] = max(0, v[j] - i);  
                j++;  
            } 
            const bool is_in = visited.find(v) != visited.end(); 
            if(is_in) continue; 
            visited.insert(v); 
            q.push({ v, cnt + 1 });
            //여기서 max를 고려한 수정이 더 필요함. - 원복
            int j = 0; 
            for(int i : {9, 3, 1}){
                v[j] = max(0, v[j] + i);  
                j++;  
            } 
        } 
        while (prev_permutation(v.begin(), v.end()));
    }
}

int main()
{
    cin >> N;
    for (int i = 0; i < N; i++)
    {
        int temp; 
        cin >> temp; 
        scv.push_back(temp); 
    }
    if(scv.size() == 1){
        scv.push_back(0);
        scv.push_back(0);
    }else if (scv.size() == 2){
        scv.push_back(0);
    }
    sort(scv.begin(), scv.end()); 
    Mutalisk();
    cout << ret;

    return 0;
}

 

또 질문 있으시면 언제든지 질문 부탁드립니다.

좋은 수강평과 별점 5점은 제게 큰 힘이 됩니다. :)

감사합니다.

강사 큰돌 올림.

요가인님의 프로필 이미지
요가인

작성한 질문수

질문하기