블로그 이미지
Nehoy
경기대학교 / kknock

calendar

1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

Notice

Tag

2020. 9. 7. 18:18 프로그래밍

게임할 때 음악을 끄거나 키러 왔다갔다 하기 귀찮아서 만들게 되었다.

 

YMC는 트레이 프로그램으로 WebSocket 서버를 열고 있다.

Extension은 Youtube Music이 틀어지게 되면, 해당 페이지에서 WebSocket을 열어 YMC 프로그램과 통신한다.

단축키를 입력하면 YMC 프로그램이 클라이언트들에게 메세지를 전송하고, 메세지를 수신한 Extension이 버튼을 누름으로써 기능을 동작한다.

 

Github - YMC: github.com/beuoon/YMC

Github - YMC_Extension: github.com/beuoon/YMC_Extension

 

크롬 스토어: https://chrome.google.com/webstore/detail/youtube-music-controller/mjmmnjpdohmbdbkjbjgiomknfmfccknh

 

Youtube Music Controller

youtube music controller

chrome.google.com

웨일 스토어: https://store.whale.naver.com/detail/lgjjfmjdfimclookhheidkbgbianandm

 

Youtube Music Controller

youtube music controller

store.whale.naver.com

 

'프로그래밍' 카테고리의 다른 글

[개인 공부] 거북이 프로그램  (2) 2017.06.07
[개인 공부] 하노이 타워  (0) 2017.05.20
posted by Nehoy
2020. 2. 22. 17:41

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2020. 2. 3. 21:55

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2020. 2. 3. 21:30

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2020. 2. 2. 01:03

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2020. 2. 1. 23:42

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2020. 1. 31. 11:10 프로그래밍/알고리즘

두 문제 다 plane sweaping 알고리즘을 사용하여 풀 수 있다.

plane sweaping 알고리즘: https://codedoc.tistory.com/421

 

plane sweeping - 직사각형 넓이합 구하기

plane sweeping 사각형 넓이 구하기 알고리즘 문제링크 : https://www.acmicpc.net/problem/3392 작성중... 아래 처럼 직사각형이 겹쳐졌을 때 색칠된 부분의 넓이 합을 구하는 것이 목표입니다. 먼저 각 직사각..

codedoc.tistory.com

plane sweaping 알고리즘의 핵심은 segment tree와 함께 sweaping 기법을 사용한다는 것이다.

자세한건 북서풍 문제로 알아보자.

 

행사장 대여 같은 경우에는 plane sweaping에서 아이디어를 착안해서 풀었다.

넓이의 합에 segment tree를 사용할 필요는 없다고 느껴, 이진 탐색 트리인 map으로 문제를 풀었다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;

class Rect {
public:
	int x1, y1, x2, y2;
};

class Line {
public:
	Line() {

	}
	Line(int x, int y1, int y2, bool bStart) :
		x(x), y1(y1), y2(y2), bStart(bStart) {

	}

	bool operator<(const Line& line) {
		return x < line.x;
	}

	int x, y1, y2;
	bool bStart;
};

class Segment {
public:
	Segment() {
		height = 0;
		startX = 0;
		count = 0;
	}

	int height;
	int startX, count;
};

istream& operator>>(istream& is, Rect& rect) {
	return is >> rect.x1 >> rect.y1 >> 
		rect.x2 >> rect.y2;
}

bool sort(const Rect& r1, const Rect& r2) {
	return (r1.x1 != r2.x1) ? r1.x1 < r2.x1 : r1.x2 < r2.x2;
}

int main() {
	int n;
	cin >> n;

	// 입력
	vector<Rect> rects(n);
	for (int i = 0; i < rects.size(); i++)
		cin >> rects[i];

	// LEFT, RIGHT 선 데이터 생성
	vector<Line> lines; // x, bottom, top
	for (int i = 0; i < rects.size(); i++) {
		lines.push_back(Line(rects[i].x1, rects[i].y1, rects[i].y2, true));
		lines.push_back(Line(rects[i].x2, rects[i].y1, rects[i].y2, false));
	}
	sort(lines.begin(), lines.end());

	// Y축 기준 세그먼트 트리 생성
	map<int, Segment> segmentMap; // y, Segment
	for (int i = 0; i < rects.size(); i++) {
		segmentMap.insert({ rects[i].y1, Segment() });
		segmentMap.insert({ rects[i].y2, Segment() });
	}

	for (auto iter = segmentMap.begin(); true; ) {
		auto prevIter = iter;
		if (++iter == segmentMap.end()) break;

		int y1 = prevIter->first;
		int y2 = iter->first;

		prevIter->second.height = y2 - y1;
	}
	segmentMap.erase(--segmentMap.end());

	long long sum = 0;
	for (int i = 0; i < lines.size(); i++) {
		auto sIter = segmentMap.lower_bound(lines[i].y1);
		auto eIter = segmentMap.lower_bound(lines[i].y2);

		for (auto iter = sIter; iter != eIter; iter++) {
			// cout << lines[i].x << " " << iter->first << endl;
			if (lines[i].bStart) {
				if (iter->second.count++ == 0)
					iter->second.startX = lines[i].x;
			}
			else {
				if (--iter->second.count == 0) {
					sum += (long long)iter->second.height * (long long)(lines[i].x - iter->second.startX);
					// cout << iter->second.startX << " ~ " << lines[i].x << ", " << iter->first << " ~ " << iter->second.height + iter->first << \
						" = " << iter->second.height * (lines[i].x - iter->second.startX) << endl;
				}
			}
		}
	}

	cout << sum << endl;
    return 0;
}

 

 

북서풍 문제 같은 경우, X좌표를 기반으로 세그먼트 트리를 생성하고 맨 오른쪽 아래 좌표부터 sweaping을 하여 풀었다.

처음에는 세그먼트 트리의 인덱스와 X 좌표의 값이 다르다 보니 각 노드에 X 좌표의 범위를 새겨줬는데, 시간 초과가 나서 다른 방법을 써야 했다. 검색을 해보니 X좌표를 인덱스 매기는 식으로 압축하면 된다하여 그렇게 했다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <cmath>
#include <cstring>
using namespace std;
class SegmentTree {
public:
	SegmentTree(int n) {
		h = (int)ceil(log2(n));
		int size = 2 << (h + 1);
		arr = new int[size];
		memset(arr, 0, sizeof(int) * size);
	}
	~SegmentTree() {
		delete[] arr;
	}
	int get(int n) {
		int index = (2 << h) + n;
		int sum = 0;
		// Leaf 노드 처리
		sum += arr[index]++;
		while (index > 0) {
			// 위로 올라 감
			int prevIndex = index;
			index /= 2;
			// 왼쪽에서 올라왔으면 오른쪽 값 더함
			if (prevIndex % 2 == 0)
				sum += arr[index * 2 + 1];
			// Sum 올림
			arr[index]++;
		}
		return sum;
	}
	int h;
	int* arr;
};
class Point {
public:
	int x, y;
	int r;
};
int main() {
	int c; cin >> c;
	while (c-- > 0) {
		int n; cin >> n;
		// 입력
		vector<Point> points(n);
		for (int i = 0; i < n; i++)
			cin >> points[i].x >> points[i].y;
		// X 좌표 순서대로 인덱스 매기기
		sort(points.begin(), points.end(), [](const Point& p1, const Point& p2) {
			return p1.x < p2.x;
		});
		int rank = 1;
		points[0].r = rank;
		for (int i = 1; i < points.size(); i++) {
			if (points[i - 1].x != points[i].x) rank++;
			points[i].r = rank;
		}
		// X 좌표 기반 세그먼트 트리 생성
		SegmentTree segmentTree(rank);
		// 맨 오른쪽 아래 좌표부터 카운트 시작
		sort(points.begin(), points.end(), [](const Point& p1, const Point& p2) {
			return (p1.y != p2.y) ? p1.y < p2.y : p1.x > p2.x;
		});
		long long answer = 0;
		for (int i = 0; i < n; i++)
			answer += segmentTree.get(points[i].r);
		cout << answer << "\n";
	}
	return 0;
}

 

시간 제한이 1초이다보니 자잘한 연산들도 다 최적화 해줘야 해서 불편했다...

그리고 처음에는 압축 방식을 unordered_map을 사용해서 했는데, 이 또한 O(kn)이라 시간 초과가 났다.

O(n)인 인덱스 매기는 방법이 유일한 방법인거 같다.

posted by Nehoy
2020. 1. 31. 10:41 프로그래밍/알고리즘

문제: https://www.acmicpc.net/problem/7662

 

7662번: 이중 우선순위 큐

문제 이중 우선순위 큐(dual priority queue)는 전형적인 우선순위 큐처럼 데이터를 삽입, 삭제할 수 있는 자료 구조이다. 전형적인 큐와의 차이점은 데이터를 삭제할 때 연산(operation) 명령에 따라 우선순위가 가장 높은 데이터 또는 가장 낮은 데이터 중 하나를 삭제하는 점이다. 이중 우선순위 큐를 위해선 두 가지 연산이 사용되는데, 하나는 데이터를 삽입하는 연산이고 다른 하나는 데이터를 삭제하는 연산이다. 데이터를 삭제하는 연산은 또

www.acmicpc.net

처음에는 두개의 우선순위 큐를 사용하면 되지 않을까 했지만, 반례가 발생해서 안됐다.

그 다음 deque을 사용해야하나 했지만 우선 순위가 적용되지 않아 안됐고, 이후 map을 생각하게 됐다.

 

STL의 map은 이진 탐색 트리로 구현이 되어있으면서, begin과 end로 최댓값, 최솟값을 가져올 수 있기 때문에 적절하다고 판단했다. key가 insert되는 실제 값이고 value는 해당 값의 count다.

 

#include <iostream>
#include <algorithm>
#include <map>

using namespace std;

int main() {
	int t; cin >> t;

	while (t-- > 0) {
		int k; cin >> k;

		map<int, int, greater<int>> que;

		for (int i = 0; i < k; i++) {
			char command; int value;
			cin >> command >> value;

			if (command == 'I') { // 삽입
				if (que.find(value) == que.end())
					que.insert({ value, 1 });
				else
					que[value]++;
			}
			else { // 삭제
				if (!que.empty()) {
					map<int, int, greater<int>>::iterator iter;
					if (value == 1)
						iter = que.begin(); // 최댓값
					else
						iter = --que.end(); // 최솟값

					if (--iter->second == 0) // count가 0이면 삭제
						que.erase(iter);
				}
			}
		}

		if (que.empty())
			cout << "EMPTY\n";
		else
			cout << que.begin()->first << " " << (--que.end())->first << "\n";
	}

	return 0;
}

간단하게 풀기는 했지만, 당연하다시피 속도가 매우 느렸다.

다른 사람의 코드를 보니 min-max heap이라는 자료구조가 나와 공부해봤는데, 신세계를 보았다.

Min-Max Heap: http://blog.naver.com/PostView.nhn?blogId=heojh93&logNo=220020760884

 

(#Tree) Min-Max Heap

Heap 이라하믄, 부모노드가 항상 자식 노드보다 작거나.. 큰.. 트리를 말한다. 따라서, Max heap, Min h...

blog.naver.com

 

Min-Max Heap을 구현하고 문제를 풀어보자.

posted by Nehoy
2020. 1. 18. 14:22

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2020. 1. 18. 13:56

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

prev 1 2 next