Problem
Problem URL : 벌꿀 채취
[1] Answer Code (18. 10. 14)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define p pair<int,int>
using namespace std;
int map[10][10];
int ans;
int n,m,c;
int cal_dfs(vector<int> v, int idx, int origin_sum, int pow_sum){
int tmp = -1;
if(idx == v.size()){
return pow_sum;
}
int _tmp;
// Include
if(origin_sum + v[idx] <= c){
_tmp = cal_dfs(v,idx+1, origin_sum + v[idx], pow_sum + (v[idx] * v[idx]));
tmp = tmp < _tmp ? _tmp : tmp;
}
// Pass
_tmp = cal_dfs(v,idx+1, origin_sum, pow_sum );
tmp = tmp < _tmp ? _tmp : tmp;
return tmp;
}
int cal(int st_row, int st_col, int end_col){
vector<int> v;
for(int i=st_col; i<=end_col; i++){
v.push_back(map[st_row][i]);
}
int ans = cal_dfs(v,0,0,0);
return ans;
}
void dfs(int st_row, int st_col, int sum, int m_cnt){
if(m_cnt == 2){
ans = ans < sum ? sum : ans;
return ;
}
for(int i=st_row; i<n; i++){
int continue_cnt = 0;
for(int j=st_col; j<n; j++){
continue_cnt ++;
if(continue_cnt == m){
continue_cnt = 0;
/*
n = 5
m = 3
row index = 1 이라고 가정하면
[ 1,0 -> 1,2 | 1,1 -> 1,3 | 1,2 -> 1,4 | 1,3 -> 1,5 ]
이렇게 체크를 해야한다.
그런데 지금 로직이라면 j=0에서 2가 됐을 때
그 다음 체크하는 위치는 j=3이 된다.
그런데 j=0일 때 체크하고 다음은 j=1일 때 체크해야한다.
그렇기 때문에 j-m+1(= 2-3+1)하게 되면 j는 0이 되고
for(;;j++) 조건에 의해서 j=1이 되고
j=1일 때 체크가 가능해진다.
*/
int tmp_sum = cal(i, j-m+1 ,j);
dfs(i,j+1,sum + tmp_sum, m_cnt + 1);
j = j-m+1;
}
}
st_col = 0;
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int TC;
cin >> TC;
for(int tc=1; tc<=TC; tc++){
memset(map,0,sizeof(map));
ans = -1;
cin >> n >> m >> c;
for(int i=0; i<n; i++) for(int j=0; j<n; j++) cin >> map[i][j];
dfs(0,0,0,0);
cout << "#" << tc << " " << ans << endl ;
}
return 0;
}
Review
-
60분이 걸렸다.
-
생각보다 어려웠네…
[2] Answer Code (18. 09. 03)
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,c;
int map[10][10];
int dp[10][10];
int cal(vector<int> &v, int idx, int sum, int profit){
if(sum > c) return 0;
if(idx == v.size()) return profit;
// 해당 idx 벌꿀을 채취했을 경우 O
int res_1 = cal(v,idx+1, sum + v[idx], profit + (v[idx] * v[idx]));
// 해당 idx 벌꿀을 채취했을 경우 X
int res_2 = cal(v,idx+1, sum, profit);
return max(res_1, res_2);
}
int getMaxCost(int x,int y){
vector<int> v;
for(int i=0; i<m; i++)
v.push_back(map[x][y+i]);
return cal(v, 0, 0, 0 );
}
int dfs(int x, int y){
int ans = -1;
// 같은 Line
for(int i=y; i<n-m+1; i++)
ans = max(ans, dp[x][i]);
// 다음 Line
for(int i=x+1; i<n; i++)
for(int j=0; j<n-m+1; j++)
ans = max(ans, dp[i][j]);
return ans;
}
int main(){
int TC;
cin >> TC;
for (int tc=1; tc<=TC; tc++) {
memset(map,0,sizeof(map));
memset(dp,0,sizeof(dp));
cin >> n >> m >> c;
for(int i=0; i<n; i++) for(int j=0; j<n; j++) scanf("%d",&map[i][j]);
/*
i,j부터 m까지 MaxCost 구하기
i = 2 | j = 3 | m = 5 일경우
dp[2][3] = map[2][3] ~ map[2][8] 사이의 최대 값을 구해놓는다.
*/
for(int i=0; i<n;i ++)
for(int j=0; j<n-m+1; j++)
dp[i][j] = getMaxCost(i, j);
int res = -1;
for(int i=0; i<n;i ++)
for(int j=0; j<n-m+1; j++)
res = max(res, dfs(i,j+m) + dp[i][j] );
printf("#%d %d\n",tc, res);
} // end of for tc
return 0;
}
Review
-
조합 계산을하는데 포기했다. 답을 찾아보다 굉장히 좋은 정답 코드를 봤다.
-
[i][j]까지 범위에서 max 값을 DP로 구해놓은 후 DFS로 정답을 찾는 로직이다.
-
조합 계산을 getMaxCost()와 cal()로 해결하였는데 너무나 좋은 학습이되었다.
[3] Answer Code (18. 06. 03)
//벌꿀채취 이준용
#include <cstdio>
#include <cstring>
using namespace std;
int T, N, M, C, AnsB, Ans, map[10][10];
void Input() {
scanf("%d %d %d", &N, &M, &C);
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
scanf("%d", &map[i][j]);
Ans = 0;
}
int Abs(int a) { return a > 0 ? a : -a; }
void PersonB(int x, int y) {
AnsB = 0;
for (int a = x; a < N; a++)
for (int b = 0; b <= N - M; b++) {
if (a == x && Abs(y - b) < M) continue;
for (int i = 1; i < (1 << M); i++) {
int SumB = 0, CheckB = 0;
for (int j = 0; j < M; j++)
if (i & (1 << j)) {
CheckB += map[a][b + j];
SumB += map[a][b + j] * map[a][b + j];
}
if (CheckB <= C && AnsB < SumB)
AnsB = SumB;
}
}
}
void PersonA(int x, int y) {
for (int i = 1; i < (1 << M); i++) { // 2n-1번 Loop
int SumA = 0, CheckA = 0;
for (int j = 0; j < M; j++)
if (i & (1 << j)) {
CheckA += map[x][y + j];
SumA += map[x][y + j] * map[x][y + j];
}
if (CheckA <= C) {
PersonB(x, y);
if (Ans < AnsB + SumA)
Ans = AnsB + SumA;
}
}
}
void CheckMap() {
for (int i = 0; i < N; i++)
for (int j = 0; j <= N - M; j++)
PersonA(i, j);
}
int main() {
scanf("%d", &T);
for (int tc = 1; tc <= T; tc++) {
Input();
CheckMap();
printf("#%d %d\n", tc, Ans);
}
}
Review
-
가로선에서 최고의 이익을 낼 수 있는 Logic을 짜는데 시간이 들었다.
-
무조건 연결된 가로가 아니라 뛰어넘을 수 있었다.
문제에 명시가 안되어 있어서 잘못 Logic을 구현 -
그런데 Input Data를 보면 TC 4를 통해 뛰어넘어도 된다는 것을 알 수 있었다.
-
Greedy 접근을 했는데 예외가 발생했다.
-
준용이의 비트마스킹으로 DFS 구현한거 보고 배우자 !