www.acmicpc.net/problem/3020

 

3020번: 개똥벌레

개똥벌레 한 마리가 장애물(석순과 종유석)로 가득찬 동굴에 들어갔다. 동굴의 길이는 N미터이고, 높이는 H미터이다. (N은 짝수) 첫 번째 장애물은 항상 석순이고, 그 다음에는 종유석과 석순이

www.acmicpc.net

많은 사람들이 lower_bound와 upper_bound함수를 사용해 이분탐색 알고리즘을 사용해 푼 것을 문제를 맞추고 나서 알 수 있었다.

 

처음엔 그냥 완탐으로 풀려다 시간 초과가 발생하는 바람에  누적합 알고리즘과 비슷하게 문제를 풀 수 있었다.

 

1. 석순과 종유석 벡터를 각각 생성 후 장애물이 마지막으로 지나는 부분의 벡터 값을 증가시켜주었다.(상한선 하한선 생성)

 

2. 그 후 크기가 1인 석순은 크기가 2인 석순을 지날 때 똑같이 부셔야 하므로 벡터의 모든 값을 갱신해주었다.

 

3. 마지막으로 두개의 벡터를 더한 값을 새로운 벡터에 넣어주고 그 벡터를 정렬 후 최소값과 그 갯수를 구할 수 있었다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	int n, h, x;
	cin >> n >> h;
	vector<int> v1(h + 1);
	vector<int> v2(h + 1);
	vector<int> v3;
	for (int i = 1; i <= n; i++) {
		cin >> x;
		if (i % 2 == 1) {
			v1[x]++;
		}
		else {
			v2[h+1-x]++;
		}
	}
	for (int i = 1; i < h; i++) {
		v2[i + 1] += v2[i];
		v1[h - i] += v1[h + 1 - i];
	}
	for (int i = 1; i <= h; i++) {
		v3.push_back(v1[i] + v2[i]);
	}
	sort(v3.begin(), v3.end());
	int cnt = 1;
	for (int i = 1; i < v3.size(); i++) {
		if (v3[0] < v3[i]) {
			break;
		}
		cnt++;
	}
	cout << v3[0] << " " << cnt;
	return 0;
}

lower_bound와 upper_bound 함수를 좀 더 공부해서 다음번엔 써먹어 봐야겠다!(하지만 속도랑 코드 크기는 별차이 안남;;)

www.acmicpc.net/problem/2470

 

2470번: 두 용액

첫째 줄에는 전체 용액의 수 N이 입력된다. N은 2 이상 100,000 이하이다. 둘째 줄에는 용액의 특성값을 나타내는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 수들은 모두 -1,000,000,000 이상 1,000,00

www.acmicpc.net

처음에 이분 탐색이라 생각하고 풀었는데 기본적인 이분탐색 구조와 살짝 다르게 구현해야해서 시간이 좀 걸린 문제이다.

 

반례를 보고 풀 수 있었는데 left = right인 경우에 같은 값이 출력되는 것을 생각 못하게 구현한 것이 패인이였다.

 

결국 기본적인 이분탐색과 다르게 left <= right형식과 mid를 사용하지 않아서 약간 변형된 문제였다.

 

또한 두 개의 용액만을 더해야 하기 때문에 투 포인터로 좀 애매할 것 같아 투 포인터를 사용하지 않았다.

 

 

1. 이분 탐색을 위해 벡터를 정렬한다.

 

2. 0과 가까운 것을 알기 위해 조건을 절댓값으로 비교해준다.

 

3. 합이 0보다 작으면 left증가 0보다 크면 right를 증가해서 값을 비교해주었다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;

vector<int> v;

int main() {
	int n, x;
	long long ans = 0;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> x;
		v.push_back(x);
	}
	sort(v.begin(), v.end());

	int left = 0;
	int right = v.size() - 1;
	ans = v[left] + v[right];
	int ans1 = left;
	int ans2 = right;
	while (left < right) {
		long long sum = v[left] + v[right];
		if (abs(ans) > abs(sum)) {
			ans = sum;
			ans1 = left;
			ans2 = right;
		}
		if (sum > 0) {
			right -= 1;
		}
		else {
			left += 1;
		}

	}
	cout << v[ans1] << " " << v[ans2];
	return 0;
}

www.acmicpc.net/problem/1477

 

1477번: 휴게소 세우기

첫째 줄에 현재 휴게소의 개수 N, 더 지으려고 하는 휴게소의 개수 M, 고속도로의 길이 L이 주어진다. N은 100보다 작거나 같으며, M도 100보다 작거나 같다. L은 100보다 크거나 같고, 1000보다 작거나

www.acmicpc.net

이분 탐색 문제를 몇개 풀어본 지라 나름 자신있게 도전을 했었다.

 

근데 우선 순위 큐를 사용해서 풀 수도 있을 것 같아 계속 하다보니 도저히 답을 구할 수 없었다.

 

그래서 결국 이분 탐색으로 풀려하는데 풀이법이 생각이 안나 다른 사람의 풀이를 결국 참고했다ㅠㅠ

 

예전에 풀었던 입국심사 문제와 조금 비슷한 면이 있는 문제 였는데 너무 생각없이 문제를 접근했던 것 같다.

 

다음 부턴 문제를 풀고 나서 확실히 이해하고 기억하는 습관을 길러야겠다

 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> v;

int main() {
	int n, m, l, x;
	cin >> n >> m >> l;
	v.push_back(0);
	for (int i = 0; i < n; i++) {
		cin >> x;
		v.push_back(x);
	}
	sort(v.begin(), v.end());
	v.push_back(l);
	
	int left = 1;
	int right = l - 1;
	int mid = 0;
	while (left <= right) {
		mid = (left + right) / 2;
		int store = 0;
		for (int i = 1; i < v.size(); i++) {
			int d = v[i] - v[i - 1];
			store += d / mid;
			if (d % mid == 0) {
				store--;
			}
		}
		if (store > m) {
			left = mid + 1;
		}
		else {
			right = mid - 1;
		}
	}

	cout << left;
	return 0;
}

참고한 블로그: paris-in-the-rain.tistory.com/44

 

[BOJ 백준] 1477 - 휴게소 세우기

https://www.acmicpc.net/problem/1477 1477번: 휴게소 세우기 첫째 줄에 현재 휴게소의 개수 N, 더 지으려고 하는 휴게소의 개수 M, 고속도로의 길이 L이 주어진다. N은 100보다 작거나 같으며, M도 100보다 작..

paris-in-the-rain.tistory.com

딱 깔끔하게 푸셔서 도움이 많이 되었다..

www.acmicpc.net/problem/1520

 

1520번: 내리막 길

여행을 떠난 세준이는 지도를 하나 구하였다. 이 지도는 아래 그림과 같이 직사각형 모양이며 여러 칸으로 나뉘어져 있다. 한 칸은 한 지점을 나타내는데 각 칸에는 그 지점의 높이가 쓰여 있으

www.acmicpc.net

처음엔 그냥 DFS로 풀려고 했지만 계속 시간 초과가 나와서 고민을 많이 했다. 그냥 DFS를 사용하면 4^(500*500)번의 연산 횟수가 나온다는 것을 잘 몰랐다..

 

결국 풀다가 도저히 안되서 답을 보고 풀 수 있었는데 DP를 bottom up형식으로 써야하는 것이 어려웠던 문제이다.

 

문제 해설 중에는 이 블로그가 이해를 하는데 많이 도움을 준 것 같다.

wootool.tistory.com/83

 

[백준][1520번][DP] 내리막길

내리막길 https://www.acmicpc.net/problem/1520 <코드> 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51..

wootool.tistory.com

결국 내가 푼 코드는

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
using namespace std;

int map[501][501];
int dp[501][501];
int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};
int m, n;

int dfs(int x, int y) {
	if (!x && !y) {
		return 1;
	}
	if (dp[x][y] == -1) {
		dp[x][y] = 0;
		for (int i = 0; i < 4; i++) {
			int a = x + dx[i];
			int b = y + dy[i];
			if (a >= 0 && b >= 0 && a < m && b < n &&
				map[a][b] > map[x][y]) {
				dp[x][y] += dfs(a, b);
			}
		}
	}
	return dp[x][y];
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cin >> m >> n;
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			cin >> map[i][j];
			dp[i][j] = -1;
		}
	}
	cout << dfs(m-1, n-1);
	return 0;
}

DP를 이런식으로 사용할 수 도 있다는 것을 알 수 있었고 아직 부족함을 많이 느끼게 해준 문제였다.. ㅠㅠ

예전에 자바로 구현해보았던 부분이지만 다시 만들어보니 생각보다 시간이 좀 걸렸다..

 

1. build.gradle의 dependencies에 코드를 추가한다.

 

dependencies {

    implementation 'com.google.android.material:material:1.2.1'

}

 

2. Floating Action Button을 추가하고자 하는 xml의 버튼 디자인 중 해당 버튼을 찾아 추가해준다.

 

<com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="60dp"
        android:layout_height="60dp"
        app:fabCustomSize="60dp"
        android:clickable="true"
        android:focusable="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.919"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.937"
        app:srcCompat="@drawable/add" />

여기서 보통은 백그라운드 이미지가 제대로 중앙에 오지 않을 것이다. 이때!

app:fabCustomSize="60dp"

width와 height 크기에 맞추어 위의 dp를 조절해 코드를 추가해주면 해결이 된다ㅎㅎ

 

 

3. 버튼을 추가한 xml을 사용하는 액티비티로 가서 새로운 액티비티를 열어주는 버튼 클릭 리스너 코드를 추가한다.

 

package com.example.desktop.mymo

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import com.google.android.material.snackbar.Snackbar

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val fab: View = findViewById(R.id.fab)		// 버튼 객체 생성
        fab.setOnClickListener {					// 클릭 리스너 생성
            val intent = Intent(this, EditActivity::class.java)	//인텐트 생성
            startActivity(intent)				//새로운 액티비티 시작
        }
    }
}

위의 과정을 거치면

 

<화면 캡처>

위와 같은 FAB를 만들 수 있다.

 

다음 번엔 버튼 색깔 및 버튼 눌렀을 때 여러개의 버튼이 나오는 방법에 대해 공부를 해봐야겠다..

예전에 안드로이드 스튜디오를 처음 사용할때도 찾아봤던 내용이다. 맨날 헷갈려서 이번에는 기록해보려고 한다.

 

처음 시작할 경우 앱의 액션바가 보이지 않는 경우가 있다.

 

그때는 xml에 들어가 눈모양에서 "Show System UI"를 클릭해주면 나온다ㅎㅎ

<액션바 보이지 않는 경우>
<액션바를 다시 보이게 만듬>

 

www.acmicpc.net/problem/11000

 

11000번: 강의실 배정

첫 번째 줄에 N이 주어진다. (1 ≤ N ≤ 200,000) 이후 N개의 줄에 Si, Ti가 주어진다. (1 ≤ Si < Ti ≤ 109)

www.acmicpc.net

처음엔 강의시간의 길이로 접근해야 된다고 생각했는데 결국 강의 종료시간과 다음 강의 시작시간을 비교하는 것이 중요하다는 것을 알게 되었다.

 

1. 각 강의들을 벡터에 저장하고 정렬해준다.

 

2. 각 강의의 종료시간을 우선순위 큐에 저장해주고 다음 강의들의 시작시간과 우선순위 큐의 top을 비교해준다.

 

3. 만 우선순위 큐의 top이 시작시간보다 작다면 강의실을 늘리고 아니면 종료시간을 pop해준다.

 

이런식으로 알고리즘을 생각하고 풀었으며 생각보다 다른 문제들과 좀 다른 유형이라 고민을 꽤 오래했다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <queue>
#include <vector>
#include <utility>
#include <algorithm>
using namespace std;

priority_queue<int, vector<int>, greater<int>> pq;
vector<pair<int, int>> v;

int main() {
	int n,x,y, ans = 0;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> x >> y;
		v.push_back({ x,y });
	}
	sort(v.begin(), v.end());
	pq.push(v[0].second);
	ans++;
	for (int i = 1; i < n; i++) {
		auto z = v[i];
		if (z.first >= pq.top()) {
			pq.pop();
		}
		else {
			ans++;
		}
		pq.push(z.second);
	}
	cout << ans;
	return 0;
}

www.acmicpc.net/problem/1715

 

1715번: 카드 정렬하기

정렬된 두 묶음의 숫자 카드가 있다고 하자. 각 묶음의 카드의 수를 A, B라 하면 보통 두 묶음을 합쳐서 하나로 만드는 데에는 A+B 번의 비교를 해야 한다. 이를테면, 20장의 숫자 카드 묶음과 30장

www.acmicpc.net

우선순위 큐 분류에 들어가 있는 골드4 난이도의 문제였다.

 

이 문제 같은 경우엔 두 묶음을 골라 합치면 비교 횟수가 줄어 드는 것을 생각하고 풀면 쉽게 풀리는 문제였다.

 

최소 우선 순위 큐에 각 카드 묶음들을 넣어주고 계속 2개씩 꺼내어 더한 후 다시 넣어주는 식으로 구현하였다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

priority_queue<int, vector<int>, greater<int>> pq;

int main() {
	int n, x, ans = 0;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> x;
		pq.push(x);
	}
	while (pq.size() > 1) {
		int a = pq.top();
		pq.pop();
		int b = pq.top();
		pq.pop();
		ans += a + b;
		pq.push(a + b);
	}
	cout << ans;
	return 0;
}

www.acmicpc.net/problem/2075

 

2075번: N번째 큰 수

첫째 줄에 N(1 ≤ N ≤ 1,500)이 주어진다. 다음 N개의 줄에는 각 줄마다 N개의 수가 주어진다. 표에 적힌 수는 -10억보다 크거나 같고, 10억보다 작거나 같은 정수이다.

www.acmicpc.net

힙 혹은 우선순위 큐에 대해서 공부를 하기 위해서 문제를 찾던 도중 발견한 문제이다.

 

그냥 기본적인 우선순위 큐를 사용해서 푸는 문제인데 메모리 제한이 있어서 이부분을 생각해

pop()을 넣어주는 것이 중요한 문제였다.

 

또한 시간 초과를 겪었는데 이 부분은 cin, cout을 사용할 경우

ios_base :: sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);

위와 같은 코드를 삽입해주어야 하고 아니면 그냥 scanf, printf를 사용해야 시간 초과가 나지 않는다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;

priority_queue<int, vector<int>, greater<int>> pq;

int main() {
	int n, x;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			scanf("%d", &x);
			pq.push(x);
			if (pq.size() > n) {
				pq.pop();
			}
		}
	}
	printf("%d", pq.top());
	return 0;
}

왜 난이도가 골드 4인지 약간 이해가 안되는 문제였다.. 아마 우선 순위 큐를 사용하지 않고 직접 구현하는 경우를 생각해서 그런 것 같다.

간단하게 앱 개발과 코틀린 공부를 같이 시작했는데 우선 간단한 로딩 화면을 생성해보았다.

 

매니패스트 파일을 우선 아래와 같이 바꾸어 주는데 상단바를 없애고 싶어서 스타일을 추가해주었다.

나머지 intent-filter는 초기 메인 액티비티에 있는 것을 복붙하면 된다.

 

<AndroidManifest.xml>

<activity android:name=".SplashActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity">
        </activity>

 

코틀린이 익숙하지 않아서 조금 헷갈리는 부분은 있지만 자바로 작성했을 때와 크게 차이가 없는 것 같다.

 

<SplashActivity.kt>

import android.content.Intent
import android.os.Bundle
import android.os.Handler
import androidx.appcompat.app.AppCompatActivity

class SplashActivity : AppCompatActivity() {

    private val SPLASH_TIME_OUT:Long = 3000
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.splash)

        Handler().postDelayed({
            startActivity(Intent(this, MainActivity::class.java))

            finish()
        }, SPLASH_TIME_OUT)
    }
}

+ Recent posts