알고리즘/1주일 1문제

2021년 3분기

tsyang 2021. 10. 22. 00:19
  1. 프래머스 - 다단계 칫솔 판매 
    더보기
    #include <string>
    #include <vector>
    #include <unordered_map>
    
    using namespace std;
    
    constexpr int PRICE = 100;
    
    vector<int> solution(vector<string> enroll, vector<string> referral, vector<string> seller, vector<int> amount) {
    	vector<int> answer;
    	answer.resize(enroll.size(), 0);
    
    	unordered_map<string, int> IDs;
    	int ID = 0;
    	for(auto en : enroll)
    		IDs[en] = ID++;
    
    	vector<int> parents(enroll.size()); //추천인을 다단계 tree상의 부모로 간주
    
    	for(int i=0;i<enroll.size();++i)
    	{
    		if(referral[i] == "-")
    			parents[i] = i;
    		else
    		{
    			int parentID = IDs[referral[i]];
    			parents[i] = parentID;
    		}
    	}
    
    	for(int i=0;i<seller.size();++i)
    	{
    		int sellerID = IDs[seller[i]];
    		int profit = PRICE * amount[i];
    		
    		while(profit>0)
    		{
    			int parentID = parents[sellerID];
    			int royalty = profit / 10;
    			profit -= royalty;
    			answer[sellerID] += profit;
    			
    			if(parentID == sellerID)
    				break;
    
    			//다음 루프에 넘김
    			profit = royalty;
    			sellerID = parentID;
    		}
    	}
    	
    	return answer;
    }
  2. 백준 11729 - 하노이 탑 이동 순서 
    더보기
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    void hanoi(int n, int from, int to, int temp)
    {
    	if (n == 0) return;
    	hanoi(n - 1, from, temp, to);
    	cout << from << ' ' << to << '\n';
    	hanoi(n - 1, temp, to, from);
    }
    
    int main()
    {
    	int n;
    	cin >> n;
    
    	cout << (int)pow(2,n) - 1 << '\n';
    	hanoi(n, 1, 3, 2);
    }
  3. 백준 - 3653 - 영화 수집 
    더보기
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    class BufferedFenwickTree
    {
    public:
    	BufferedFenwickTree(int n, int m) : tree_size_{ n+m+1 }, n_{n}, m_{m}, cur_idx_{0}
    	{
    		dvd_pos_.resize(n + 1, 0);
    		tree_.resize(tree_size_ + 1, 0);
    		
    		for (int i = 1; i <= n; ++i)
    		{
    			dvd_pos_[i] = i + m;
    			Add(i + m, 1);
    		}
    	}
    
    public:
    	int Watch(int dvd)
    	{
    		const int dvd_pos = dvd_pos_[dvd];
    		const int ret = Sum(dvd_pos) - 1;
    
    		dvd_pos_[dvd] = m_ - cur_idx_;
    		cur_idx_++;
    		
    		Add(dvd_pos, -1);
    		Add(dvd_pos_[dvd], 1);
    
    		return ret;
    	}
    
    private :
    	int Sum(int pos)
    	{
    		int result = 0;
    		while (pos > 0)
    		{
    			result += tree_[pos];
    			pos -= (pos & -pos);
    		}
    		return result;
    	}
    
    	void Add(int pos, int val)
    	{
    		while (pos <= tree_size_)
    		{
    			tree_[pos] += val;
    			pos += (pos & -pos);
    		}
    	}
    
    private:
    	int tree_size_, n_, m_, cur_idx_;
    	vector<int> tree_, dvd_pos_;
    };
    
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    
    	int num_test_case;
    	cin >> num_test_case;
    
    	while (num_test_case-- > 0)
    	{
    		int n, m;
    		cin >> n >> m;
    
    		BufferedFenwickTree bft(n,m);
    
    		for (int i = 1; i <= m; ++i)
    		{
    			int dvd;
    			cin >> dvd;
    			cout << bft.Watch(dvd) << ' ';
    		}
    		cout << "\n";
    	}
    
    	return 0;
    }
  4. 백준 2934 - LRH 식물 (펜윅트리)
    더보기
    #include <iostream>
    #include <vector>
    
    using namespace std;
    using LL = long long;
    
    class BIT //binary-indexed(fenwick) tree
    {
    public:
    	BIT() = delete;
    	explicit BIT(int n) : size_{ n }
    	{
    		tree_.resize(n + 1, 0);
    	}
    
    	LL PlantAndGetFlowers(int L, int R)
    	{
    		LL flowers_left = GetValue(L);
    		LL flowers_right = GetValue(R);
    		AddRange(L, L, -flowers_left);
    		AddRange(R, R, -flowers_right);
    		
    		AddRange(L + 1, R - 1, 1);
    		return flowers_left + flowers_right;
    	}
    
    private:
    	void AddRange(int left, int right, LL val)
    	{
    		if (left > right)
    			return;
    		
    		AddValueFromStart(right, val);
    		AddValueFromStart(left - 1, -val);
    	}
    	void AddValueFromStart(int dest_pos, LL val)
    	{
    		int idx = dest_pos;
    		while(idx > 0)
    		{
    			tree_[idx] += val;
    			idx &= idx - 1;
    		}
    	}
    	LL GetValue(int pos)
    	{
    		int idx = pos;
    		LL ret = 0;
    		while(idx <= size_)
    		{
    			ret += tree_[idx];
    			idx += (idx & -idx);
    		}
    		return ret;
    	}
    private:
    	vector<LL> tree_;
    	int size_;
    };
    
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    
    	int N, L, R;
    	cin >> N;
    	BIT bit{ 100000 };
    	for(int i=0;i<N;++i)
    	{
    		cin >> L >> R;
    		cout << bit.PlantAndGetFlowers(L, R) << "\n";
    	}
    	return 0;
    }
  5. 백준 1766 - 문제집 (위상 정렬)
    더보기
    #include <vector>
    #include <iostream>
    #include <queue>
    #include <algorithm>
    
    using namespace std;
    
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    	
    	int N, M;
    	cin >> N >> M;
    
    	vector<vector<int>> graph(N+1);
    	vector<int> indegrees(N + 1, 0);
    	vector<int> answer;
    	
    	while(M-->0)
    	{
    		int A, B;
    		cin >> A >> B;
    		graph[A].emplace_back(B);
    		indegrees[B]++;
    	}
    
    	priority_queue<int, vector<int>, greater<>> pq;
    
    	for(int i=1;i<=N;++i)
    	{
    		if (indegrees[i] == 0)
    			pq.emplace(i);
    	}
    
    	while(false == pq.empty())
    	{
    		int cur_num = pq.top(); pq.pop();
    		answer.emplace_back(cur_num);
    
    		std::for_each(graph[cur_num].begin(), graph[cur_num].end(),
    			[&indegrees, &pq](int next){if (--indegrees[next] == 0) pq.emplace(next);});
    	}
    	
    	std::for_each(answer.begin(), answer.end(), [](int ans) {cout << ans << ' '; });
    	
    	return 0;
    }
  6. 백준 2261 - 가장 가까운 두 점 (분할정복, 스위핑)
    더보기
    #include <vector>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <cmath>
    
    using namespace std;
    
    struct Point
    {
    
    public:
    	Point(int x, int y) : x{ x }, y{ y }{}
    
    	int SqrDist(Point & other) const
    	{
    		int dx = this->x - other.x;
    		int dy = this->y - other.y;
    		return dx * dx + dy * dy;
    	}
    
    	//x를 기준으로 정렬함.
    	bool operator < (const Point & other) const
    	{
    		return OrderByX(*this, other);
    	}
    
    	static bool OrderByY(const Point& p1, const Point& p2)
    	{
    		if (p1.y < p2.y)	return true;
    		if (p1.y == p2.y && p1.x < p2.x)	return true;
    		return false;
    	}
    
    	static bool OrderByX(const Point& p1, const Point& p2)
    	{
    		if (p1.x < p2.x)	return true;
    		if (p1.x == p2.x && p1.y < p2.y)	return true;
    		return false;
    	}
    
    
    public:
    	int x, y;
    };
    
    int main()
    {
    	int N;
    	cin >> N;
    
    	vector<Point> points;
    	points.reserve(N);
    
    	for(int i=0;i<N;++i)
    	{
    		int x, y;
    		cin >> x >> y;
    		points.emplace_back(x, y);
    	}
    
    	//y를 기준으로 정렬함.
    	sort(points.begin(), points.end(), Point::OrderByY);
    
    	set<Point> s;
    	s.insert(points[0]);
    	s.insert(points[1]);
    
    	int dist = points[0].SqrDist(points[1]);
    	int startIdx = 0;
    	for (int i = 2; i < N; ++i) {
    
    		//y가 이미 거리보다 차이 많이나면 목록에서 제거
    		while (startIdx < i)
    		{
    			int dy = points[i].y - points[startIdx].y;
    			if(dy*dy > dist)
    				s.erase(points[startIdx++]);
    			else
    				break;
    		}
    
    		//x 좌표가 거리 사이에 있는 모든 좌표 순회하며 거리 업데이트
    		const auto lb = s.lower_bound({ points[i].x - static_cast<int>(sqrt(dist)), -INT32_MAX });
    		const auto ub = s.upper_bound({ points[i].x + static_cast<int>(sqrt(dist)), INT32_MAX });
    		for (auto j = lb; j != ub; ++j)
    		{
    			auto curP = *j;
    			dist = min(dist, points[i].SqrDist(curP));
    		}
    
    		s.insert(points[i]);
    	}
    	cout << dist;
    }
  7. 백준 1939 - 중량 제한 (파라메트릭 서치)
    더보기
    #include <iostream>
    #include <vector>
    #include <unordered_map>
    #include <queue>
    #include <cstring>
    #include <set>
    #include <algorithm>
    
    using namespace std;
    
    constexpr int MAX_N = 10001;
    
    int N, M, S, E;
    
    //pair<int,int> 의 hash funciton
    struct hash_pair
    {
    	std::size_t operator() (const pair<int, int>& p) const
    	{
    		return (p.first * MAX_N) + p.second;
    	}
    };
    
    //TODO : 섬 A,B 에 다리가 여러개인 경우 하나만 저장하려고 이렇게 했는데 그냥 다 검사하는게 빠름
    unordered_map<pair<int,int>, int, hash_pair> weights;
    
    //TODO : 다리 목록 순회할때 weight 로 정렬해주면 최적화 가능.
    vector<vector<int>> bridges;
    
    bool bfs_visit(int weight)
    {
    	bool enqueued[MAX_N];
    	memset(enqueued, 0, sizeof(enqueued));
    
    	queue<int> q;
    	q.emplace(S);
    
    	while(false == q.empty())
    	{
    		int cur = q.front(); q.pop();
    		
    		for(auto next : bridges[cur])
    		{
    			if (enqueued[next] == true) continue;
    			
    			auto bridge = cur < next ? std::make_pair(cur, next) : std::make_pair(next, cur);
    			if(weights[bridge] >= weight)
    			{
    				if (next == E)	return true;
    				q.emplace(next);
    				enqueued[next] = true;
    			}
    		}
    	}
    	return false;
    }
    
    int main()
    {
    	cin >> N >> M;
    
    	bridges.resize(N + 1);
    	
    	while(M-->0)
    	{
    		int A, B, C;
    		cin >> A >> B >> C;
    		if (A > B)
    			swap(A, B);
    		auto bridge = std::make_pair(A, B);
    
    		//새로 추가됨
    		if(0 == weights[bridge])
    		{
    			bridges[A].emplace_back(B);
    			bridges[B].emplace_back(A);
    		}
    		
    		if (C > weights[bridge])
    			weights[bridge] = C;
    	}
    
    	cin >> S >> E;
    
    	int answer = 0;
    	int l = 1, r = 1000000000;
    	while(l<=r)
    	{
    		int mid = (l + r) / 2;
    		if(bfs_visit(mid))
    		{
    			 answer = mid;
    			l = mid + 1;
    		}
    		else
    		{
    			r = mid - 1;
    		}
    	}
    	cout << answer << endl;
    		
    	return 0;
    }
  8. 백준 9250 - 문자열 집합 판별 (아호코라식)
    더보기
    #include <iostream>
    #include <vector>
    #include <string>
    #include <queue>
    
    using namespace std;
    
    struct TrieNode
    {
    public:
    	TrieNode()
    	{
    		nexts.resize(26, nullptr);
    	}
    	~TrieNode()
    	{
    		for(auto node : nexts)
    		{
    			if (node != nullptr)
    				delete(node);
    		}
    	}
    	
    public:
    	vector<TrieNode*> nexts;
    	TrieNode* fail = nullptr;
    	bool is_end = false;
    };
    
    void add_to_trie(TrieNode & root, string && str)
    {
    	TrieNode * cur_node = &root;
    
    	for (char c : str)
    	{
    		const int idx = c - 'a';
    		if(cur_node->nexts[idx] == nullptr)
    			cur_node->nexts[idx] = new TrieNode();
    
    		cur_node = cur_node->nexts[idx];
    
    		//이미 종결된 다른 문자를 포함한 경우 더 저장할 필요 x
    		if (cur_node->is_end)	return;
    	}
    	cur_node->is_end = true;
    }
    
    void set_fail_trie(TrieNode* root)
    {
    	queue<TrieNode*> q;
    	for(auto next : root->nexts)
    	{
    		if (next == nullptr) continue;
    		next->fail = root;
    		q.emplace(next);
    	}
    	
    	while(false == q.empty())
    	{
    		auto cur_node = q.front(); q.pop();
    		auto nexts = cur_node->nexts;
    		for(int i=0;i<26;++i)
    		{
    			auto next_node = nexts[i];
    			if (next_node == nullptr) continue;
    
    			next_node->fail = root;
    
    			auto prevs_fail_node = cur_node->fail;
    			while(prevs_fail_node!=nullptr)
    			{
    				if (prevs_fail_node->nexts[i] != nullptr)
    				{
    					next_node->fail = prevs_fail_node->nexts[i];
    					break;
    				}
    				prevs_fail_node = prevs_fail_node->fail;
    			}
    
    			//fail_node가 종결이면 나도 종결임.
    			if (next_node->fail->is_end)
    				next_node->is_end = true;
    			
    			q.emplace(next_node);
    		}
    	}
    }
    
    string contains(string && str, TrieNode* root)
    {
    	TrieNode * cur_node = root;
    	for(auto c : str)
    	{
    		int idx = c - 'a';
    		while(true)
    		{
    			if (cur_node->nexts[idx] != nullptr)
    			{
    				cur_node = cur_node->nexts[idx];
    				break;
    			}
    			if (cur_node == root)
    				break;
    			cur_node = cur_node->fail;
    		}
    		if(cur_node->is_end)
    			return "YES\n";
    	}
    	return "NO\n";
    }
    
    
    int main()
    {
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    	ios::sync_with_stdio(false);
    	int N;
    	cin >> N;
    	TrieNode root;
    	for(int i=0;i<N;++i)
    	{
    		string str_in_s;
    		cin >> str_in_s;
    		add_to_trie(root, std::move(str_in_s));
    	}
    	set_fail_trie(&root);
    
    	int Q;
    	cin >> Q;
    	for(int i=0;i<Q;++i)
    	{
    		string str_in_q;
    		cin >> str_in_q;
    		cout << contains(std::move(str_in_q), &root);
    	}
    
    	return 0;
    }
  9. 프로그래머스 - 퍼즐 조각 채우기 
    더보기
    //https://programmers.co.kr/learn/courses/30/lessons/84021
    
    #include <vector>
    #include <unordered_map>
    #include <queue>
    
    using namespace std;
    
    /*
     * ///////////////////////////////////////////////////////////////////////////////////////////////////////
     *																										//
     *	모양은 최대 6칸이므로, 하나의 int로 정의할 수 있다.													//
     *	하나의 모양은 높이, 너비를 각각 3비트씩 할당하고 나머지 모양을 1비트씩 할당해서 만들 수 있다.		//
     *	모양은 key로 구분할 수 있다.																		//
     *	key는 모양을 회전시켜서 얻을 수 있는 int값의 최소값이다.											//
     *																										//
     *////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    unordered_map<int, int> shape_keys;
    
    vector<pair<int,int>> dirs = { {0,1}, {0,-1},{1,0},{-1,0} };
    
    //shape로 key를 얻어옴.
    //shape 맨 앞에 3비트씩 각각 높이, 너비를 저장
    //그 후로 각 shape마다 1비트씩 값 저장
    int GetShapeKey(const vector<vector<bool>> & shape)
    {
    	int h = shape.size();
    	int w = shape[0].size();
    
    	int key = 0;
    	
    	key += h;
    	key = key << 3;
    
    	key += w;
    	key = key << 3;
    	
    	for(int i=0;i<h;++i)
    		for(int j=0;j<w;++j)
    		{
    			key += shape[i][j];
    			key = key << 1;
    		}
    
    	return key;
    }
    
    //시계방향으로 90도 회전시킴
    void Rotate(vector<vector<bool>> & shape)
    {
    	int h = shape.size();
    	int w = shape[0].size();
    
    	vector<vector<bool>> newShape(w, vector<bool>(h));
    
    	for (int i = 0; i < h; ++i)
    		for (int j = 0; j < w; ++j)
    			newShape[j][h - 1 - i] = shape[i][j];
    
    	shape = newShape;
    }
    
    //원시적인 형태의 shape 구함
    vector<pair<int, int>> GetPrimitiveShape(vector<vector<int>> board, int blockVal, int y, int x)
    {
    	int h = board.size();
    	int w = board[0].size();
    	int notBlockVal = blockVal == 0 ? 1 : 0;
    	vector<pair<int, int>> points;
    
    	board[y][x] = notBlockVal;
    	points.emplace_back(y, x);
    
    	queue<pair<int, int>> q;
    	q.emplace(y, x);
    
    	while (false == q.empty())
    	{
    		auto curPoint = q.front(); q.pop();
    		for (auto dir : dirs)
    		{
    			int newX = curPoint.second + dir.second;
    			int newY = curPoint.first + dir.first;
    
    			if (newX < 0 || newX >= w || newY < 0 || newY >= h)
    				continue;
    			
    			if (board[newY][newX] == blockVal)
    			{
    				points.emplace_back(newY, newX);
    				q.emplace(newY, newX);
    				board[newY][newX] = notBlockVal;
    			}
    		}
    	}
    
    	return points;
    }
    
    //다듬어진 형태의 shape로 변환
    vector<vector<bool>> ToShape(const vector<pair<int, int>> & points)
    {
    	int minX = points[0].second;
    	int minY = points[0].first;
    	int maxX = points[0].second;
    	int maxY = points[0].first;
    
    	for (auto point : points)
    	{
    		int x = point.second;
    		int y = point.first;
    
    		if (y < minY) minY = y;
    		else if (y > maxY) maxY = y;
    		if (x < minX) minX = x;
    		else if (x > maxX) maxX = x;
    
    	}
    
    	vector<vector<bool>> shape(maxY - minY + 1, vector<bool>(maxX - minX + 1, 0));
    
    	for (auto point : points)
    	{
    		int x = point.second - minX;
    		int y = point.first - minY;
    		shape[y][x] = true;
    	}
    
    	return shape;
    }
    
    
    int solution(vector<vector<int>> game_board, vector<vector<int>> table) {
    	int h = game_board.size();
    	int w = game_board[0].size();
    
    	for(int i=0;i<h;++i)
    	{
    		for(int j=0;j<w;++j)
    		{
    			if(game_board[i][j] == 0)
    			{
    				auto primitive = GetPrimitiveShape(game_board, 0, i, j);
    				auto shape = ToShape(primitive);
    
    				int key = GetShapeKey(shape);
    				for(int i=0;i<3;++i)
    				{
    					Rotate(shape);
    					int newKey = GetShapeKey(shape);
    					if (newKey < key) key = newKey;
    				}
    
    				shape_keys[key]++;
    			}
    		}
    	}
    
    	int match_cnt = 0;
    	
    	for (int i = 0; i < h; ++i)
    	{
    		for (int j = 0; j < w; ++j)
    		{
    			if (table[i][j] == 1)
    			{
    				auto primitive = GetPrimitiveShape(table, 1, i, j);
    				auto shape = ToShape(primitive);
    
    				int key = GetShapeKey(shape);
    				for (int i = 0; i < 3; ++i)
    				{
    					Rotate(shape);
    					int newKey = GetShapeKey(shape);
    					if (newKey < key) key = newKey;
    				}
    				if(shape_keys[key] > 0)
    				{
    					shape_keys[key]--;
    					match_cnt++;
    				}
    			}
    		}
    	}
    	return match_cnt;
    }
  10. 백준 3033 - 가장 긴 문자열 (라빈 카프 알고리즘)
    더보기
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cmath>
    using namespace std;
    
    class RabinKarpString
    {
    public:
    	RabinKarpString(string && s)
    	{
    		str_ = std::move(s);
    	}
    
    	bool HasRepeatedSubstrOfWhichLengthIs(int substr_len)
    	{
    		vector<vector<int>> substr_hash(HASH_SIZE);
    		
    		int power = pow_MOD(substr_len - 1);
    		
    		int curH = GetHashCodeSubstr(0, substr_len);
    		substr_hash[curH].emplace_back(0);
    
    		auto curSubStr = str_.substr(0, substr_len);
    		for (int i = 1; i <= str_.size() - substr_len; ++i)
    		{
    			curH = GetHashCodeSubstrQuick(curH, i, substr_len, power);
    
    			if (false == substr_hash[curH].empty())
    			{
    				for (auto offset : substr_hash[curH])
    					if (strncmp(&str_[offset], &str_[i], substr_len - 1) == 0)
    						return true;
    			}
    
    			substr_hash[curH].emplace_back(i);
    		}
    		return false;
    	}
    
    private:
    	int GetHashCodeSubstr(int start_idx, int M)
    	{
    		long long hash = 0;
    		long long rabin_fingerprint_x = 1;
    		for (int i = start_idx + M - 1; i >= start_idx; --i)
    		{
    			hash += str_[i] * rabin_fingerprint_x;
    			hash = MOD(hash);
    			rabin_fingerprint_x = MOD(rabin_fingerprint_x * RABIN_FINGERPRINT_X);
    		}
    		return MOD(hash);
    	}
    
    	int GetHashCodeSubstrQuick(int prev_hash, int start_idx, int M, long long power)
    	{
    		return MOD(2 * (prev_hash - str_[start_idx - 1] * power) + str_[start_idx + M - 1]);
    	}
    	
    	static int pow_MOD(int pow)
    	{
    		int power = 1;
    		for (int i = 0; i < pow ; i++)
    				power = MOD(power * RABIN_FINGERPRINT_X);
    		return power;
    	}
    
    	static int MOD(const long long num)
    	{
    		if (num >= 0) { return num % HASH_SIZE; }
    		else { return ((-num / HASH_SIZE + 1)*HASH_SIZE + num) % HASH_SIZE; }
    	}
    
    private:
    	static const int HASH_SIZE = 100003;
    	static const int RABIN_FINGERPRINT_X = 2;
    	string str_;
    };
    
    int main()
    {
    	int len;
    	string str;
    	cin >> len >> str;
    
    	RabinKarpString S(std::move(str));
    
    	int left = 0, right = len;
    	while (left + 1 < right)
    	{
    		const int mid = (left + right) / 2;
    
    		if (S.HasRepeatedSubstrOfWhichLengthIs(mid))
    			left = mid;
    		else
    			right = mid;
    	}
    	cout << left << endl;
    
    	return 0;
    }
  11. 백준 1102 - 발전소 (비트, DP)
    더보기
    #include<iostream>
    #include<vector>
    #include <string>
    #include <queue>
    
    using namespace std;
    
    const short INF = 50*16;
    
    int main()
    {
    	int N, P;
    	cin >> N;
    
    	vector<bool> isOnAtFirst(N);
    	vector<vector<short>> costs(N, vector<short>(N));
    	vector<short> dp(1 << N, INF);
    
    	for (int i = 0; i < N; ++i)
    		for (int j = 0; j < N; ++j)
    			cin >> costs[i][j];
    
    	string temp;
    	cin >> temp;
    
    	int cur_state = 0;
    	int num_gens_on = 0;
    
    	for (int i = 0; i < N; ++i)
    		if (temp[i] == 'Y')
    		{
    			cur_state += 1 << i;
    			num_gens_on++;
    		}
    
    
    	cin >> P;
    
    	if(P==0)
    	{
    		cout << 0;
    		return 0;
    	}
    	if (num_gens_on == 0)
    	{
    		cout << -1;
    		return 0;
    	}
    	if(num_gens_on >= P)
    	{
    		cout << 0;
    		return 0;
    	}
    
    	dp[cur_state] = 0;
    
    	//bottom-up 식으로
    	queue<int> q;
    	queue<int> next_q;
    	q.emplace(cur_state);
    	short answer = INF;
    	while (false == q.empty())
    	{
    		cur_state = q.front(); q.pop();
    
    		if (num_gens_on == P)
    		{
    			answer = min(dp[cur_state], answer);
    		}
    		else
    		{
    			for (int i = 0; i < N; ++i)
    			{
    				int target_gen = 1 << i;
    
    				if ((cur_state & target_gen) == 0)
    				{
    					short min_cost = INF;
    					for (int j = 0; j < N; ++j)
    					{
    						int gen_on = 1 << j;
    						if ((cur_state & gen_on) > 0)
    						{
    							if (costs[j][i] < min_cost)
    								min_cost = costs[j][i];	//캐시 미스 많이 발생할까?
    						}
    					}
    
    					int new_state = cur_state + target_gen;
    					bool can_emplace = dp[new_state] == INF;
    					short new_cost = dp[cur_state] + min_cost;
    					dp[new_state] = min(dp[new_state], new_cost);
    					if(can_emplace)
    						next_q.emplace(new_state);
    				}
    			}
    
    			if (q.empty())
    			{
    				auto temp = q;
    				q = next_q;
    				next_q = temp;
    				num_gens_on++;
    			}
    		}
    	}
    
    	cout << answer;
    
    	return 0;
    }
  12. 백준 17435 - 합성함수와 쿼리 (희소 테이블)
    더보기
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    const int MAX_EXPONENT = 19;
    
    int f(int n, int x, const vector<vector<int>>& f_exp)
    {
    	int cur_exponent = MAX_EXPONENT;
    
    	while(n>0)
    	{
    		int cur_num = 1 << cur_exponent;
    		if(cur_num <= n)
    		{
    			n -= cur_num;
    			x = f_exp[cur_exponent][x];
    		}
    		--cur_exponent;
    	}
    	return x;
    }
    
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    	
    	int m;
    	cin >> m;
    	vector<vector<int>> f_exp(MAX_EXPONENT+1, vector<int>(m+1));
    	
    	for(int m_idx = 1 ; m_idx<=m ; ++m_idx)
    		cin >> f_exp[0][m_idx];
    
    	for(int i=1;i<=MAX_EXPONENT;++i)
    		for (int m_idx = 1; m_idx <= m; ++m_idx)
    			f_exp[i][m_idx] = f_exp[i-1][f_exp[i - 1][m_idx]];
    
    	int Q;
    	cin >> Q;
    
    	for(int q_cnt=0 ; q_cnt<Q ; ++q_cnt)
    	{
    		int n, x;
    		cin >> n >> x;
    		cout << f(n, x, f_exp) << "\n";
    	}
    
    	return 0;
    }

 

'알고리즘 > 1주일 1문제' 카테고리의 다른 글

2022년 1분기  (0) 2023.01.23
2021년 4분기  (0) 2022.02.20
2021년 2분기  (0) 2021.10.22
2021년 1분기  (1) 2021.01.24
2020년 4분기  (0) 2021.01.24