오늘도 열심히 그리디를 하자.
1. BOJ 2759 - 팬케이크 뒤집기 (G4)
2759번: 팬케이크 뒤집기
첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 숫자 여러개가 공백으로 구분되어있다. 첫 번째 숫자는 팬케이크의 개수 N이고, 그 다음 N개의 숫자는 팬케이크의 크기이다.
www.acmicpc.net
sol) constructive(그리디 스타일)
자명하게도 n번 팬케이크가 n번 위치에 있지 않으면 반드시 n번 팬케이크를 1번으로 옮긴 후, n번으로 옮겨야 한다.
이렇게 옮기고 나면 n-1번 팬케이크가 n-1번 위치에 있는지 판별하는 문제로 바뀐다.
위 과정을 계속 반복하면 된다.
이때 1번 위치에서는 뒤집어도 상태가 똑같으므로 굳이 뒤집을 필요가 없다. 이를 고려하면 최악의 경우에도 2n-3번 이하로 뒤집게 된다.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fast ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define all(x) x.begin(), x.end()
#define rll(x) x.rbegin(), x.rend()
#define comp(x) x.erase(unique(all(x)), x.end())
#define MOD 1000000007
ll n;
int main(){
fast;
ll t; cin>>t;
while(t--){
cin>>n;
vector<ll> v(n), ans;
for(auto &i : v)cin>>i;
for(int i = n-1 ; i >= 0 ; i--){
if(v[i]==i+1)continue;
ll j;
for(j = 0 ; j < n ; j++){
if(v[j]==i+1)break;
}
if(j)ans.push_back(j+1);
if(i)ans.push_back(i+1);
reverse(v.begin(), v.begin()+j+1);
reverse(v.begin(), v.begin()+i+1);
}
cout<<ans.size()<<" ";
for(auto i : ans)cout<<i<<" "; cout<<"\n";
}
}
2 - BOJ 17942 : 알고리즘 공부 (G1)
골드 1 그리디가 왤케 많은지 모르겠다.
sol)파라메트릭 서치 + BFS or 그리디 + 탐색
그리디 풀이도 생각났지만 파라메트릭 풀이가 더 확실해 보여서 코드는 파라메트릭으로 풀었다.
일단 그리디 풀이는 다음과 같다.
먼저 공부량이 가장 작은 알고리즘은 들어가도 손해를 보지 않는다. 왜냐하면 나중에 공부량이 깎여서 나중에 가장 작은 알고리즘보다 더 작은 비용인 알고리즘이 생길 순 있지만, 그러한 알고리즘이 생기려면 공부량이 가장 작은 알고리즘 이상의 공부량을 요구하는 알고리즘이 필요하기 때문이다. 따라서 작은 알고리즘부터 넣으면서, 공부량이 깎이는 것을 모두 체크한 후 또 가장 작은 공부량을 넣는 과정을 우선순위 큐로 반복하면 된다.
파라메트릭 풀이는 다음과 같다.
f(x) := 공부량을 x 이하로만 구성할 때 m개 이상을 공부할 수 있는가? (bool)
f(x)는 다음과 같이 동작한다.
(1) 먼저 x 이하의 모든 알고리즘을 고른다.
(2) m 이상을 골랐다면 바로 true이고, 미만을 골랐다면 고른 알고리즘들을 모두 큐에 넣은 후, bfs로 탐색하면서 공부량을 감소시키고, x이하로 감소한 알고리즘들을 더 넣는다.
(3) (2)까지 끝났을 때 m 이상이면 true, 아니면 false를 리턴한다.
따라서 x에 대한 이분탐색을 통해 최적해를 구할 수 있다.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fast ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define all(x) x.begin(), x.end()
#define rll(x) x.rbegin(), x.rend()
#define comp(x) x.erase(unique(all(x)), x.end())
#define MOD 1000000007
ll n, m;
vector<ll> v;
vector<pair<ll,ll>> adj[101010];
bool f(ll x){
ll cnt = 0;
vector<bool> sel(n, 0), visited(n,0);
for(int i = 0 ; i < n ; i++)if(v[i]<=x)cnt++, sel[i]=1;
if(cnt>=m)return 1;
queue<ll> q;
auto e = v;
for(int i = 0 ; i < n ; i++)if(sel[i])q.push(i), visited[i]=1;
while(q.size()){
ll cur = q.front();
q.pop();
for(auto [next, w] : adj[cur]){
e[next] -= w;
if(e[next]<=x){
if(visited[next])continue;
visited[next]=1;
q.push(next);
sel[next]=1;
cnt++;
}
}
}
return cnt>=m;
}
int main(){
fast;
cin>>n>>m;
v.resize(n); for(auto &i : v)cin>>i;
ll k; cin>>k;
while(k--){
ll a,b,c; cin>>a>>b>>c; a--; b--;
adj[a].push_back({b,c});
}
ll l = -1, r = 1e8+1;
while(l+1 < r){
ll mid = l+r>>1;
if(f(mid))r = mid;
else l = mid;
}
cout<<r;
}
3. BOJ 2405 - 세 수, 두 M (G4)
2405번: 세 수, 두 M
n개의 정수 A[1], A[2], …, A[n]이 있다. 서로 다른 세 정수 i, j, k에 대해서 a = A[i], b = A[j], c = A[k]라 하자. 세 수의 중위(Median)값은 정렬했을 때 가운데에 오는 수가 된다. 세 수의 평균(Mean)값은 (a+b+c)
www.acmicpc.net
그나마 쉬운(?) 그리디이다. 사실 그리디는 모두 어렵다
sol) 그리디
일반성을 잃지 않고 세 수 a,b,c(a>=b>=c)를 골랐다고 하자. 이를 위해 배열은 정렬했다고 가정하자.
이때 최대화해야하는 값은
이때 차이의 3배를 출력해야 하므로 식을 정리하면
이제 이 식의 최댓값을 구해야하는데, 먼저 절댓값의 성질에 따라 2b-a-c와 a+c-2b로 나뉜다.
(i)2b-a-c
c는 가장 작은 값을 고르면 되고, b<=a이므로 a는 b 바로 뒤의 수가 되면 2b-a가 최대이다.
즉 b를 정할때마다 a의 최적값은 자동으로 결정되므로 O(N)에 2b-a의 최댓값을 구할 수 있고, 2b-a-c의 최댓값을 구할 수 있다.
(ii)a+c-2b
(i)과 비슷하게 c를 정할 때마다 b의 최적값이 자동 결정되고, a는 가장 큰 값을 고르면 된다. O(N)에 a+c-2b의 최댓값을 구할 수 있다.
시간복잡도는 정렬이 지배하므로 O(NlogN)이 된다.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fast ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define all(x) x.begin(), x.end()
#define rll(x) x.rbegin(), x.rend()
#define comp(x) x.erase(unique(all(x)), x.end())
#define MOD 1000000007
ll n;
int main(){
fast;
cin>>n;
vector<ll> v(n);
for(auto &i : v)cin>>i;
sort(all(v));
ll ans = -1e18;
for(int i = 1 ; i < n-1 ; i++){
ans = max(ans, 2*v[i]-v[i+1]);
}
ll res = ans-v[0];
ans = -1e18;
for(int i = 0 ; i < n-2 ; i++){
ans = max(ans, v[i]-2*v[i+1]);
}
res = max(res, ans+v.back());
cout<<res;
}

슬슬 머리아파
'백준 > 랜디' 카테고리의 다른 글
골드 그리디 랜덤 (1) (0) | 2023.06.19 |
---|