[백준 1052번 C/C++] 물병

 

https://www.acmicpc.net/problem/1052


 

 

해결전

 

수학
그리디 알고리즘
비트마스킹

 

각 물병은 서로 다른 물병과 합쳐질 수 있다. 이 합치는 과정은 물병의 2진수로 표현한다.

  • 예를 들어, 물병 3개(2진수로 11)를 2개씩 합치면 2진수 100이 되어 물병 1개가 된다.

 

물병을 모두 합쳐서 k개의 물병 이하로 만들어야 한다.

  • n이 k보다 작거나 같으면 추가 물병이 필요 없으므로 0을 반환합니다.
  • 비트마스킹
    • n의 2진수 표현에서 1의 개수는 현재 물병의 수가 어떻게 조합될 수 있는지를 나타낸다.
      • int BitCnt(int x)
    • n의 2진수 표현에서 1의 개수가 k보다 많으면, 물병을 추가하여 이 개수를 줄여야 한다. 이를 위해 n을 하나씩 증가시키면서 1의 개수가 k 이하가 될 때까지 반복한다.
      • while( BitCnt(temp) > k )

 

 

정답코드

 

#include <iostream>
using namespace std;
int n, k; // n: 현재 물병 수, k: 하나로 만들 수 있는 물병의 최대 수
int answer; // 필요한 추가 물병 수
// 주어진 정수 x의 2진수 표현에서 1의 개수를 세는 함수
int BitCnt(int x)
{
int cnt = 0; // 1의 개수를 세기 위한 변수
while(x)
{
cnt += (x & 1); // x의 마지막 비트가 1이면 cnt를 증가
x >>= 1; // x를 오른쪽으로 1비트 이동
}
return cnt;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> k;
if (n <= k){ // 현재 물병 수가 k 이하이면 추가 물병이 필요 없으므로
cout << "0"; // 0을 출력
return 0;
}
int temp = n;
while (BitCnt(temp) > k) // temp의 2진수 표현에서 1의 개수가 k보다 많으면
{
temp++;
answer++; // 필요한 추가 물병 수를 1 증가
}
cout << answer;
return 0;
}

 

 

코드 비교 

 

주어진 정수 x의 2진수 표현에서 1의 개수를 세는 함수


비트마스킹 형태의 표기

int BitCnt(int x)
{
int cnt = 0; // 1의 개수를 세기 위한 변수
while(x)
{
cnt += (x & 1); // x의 마지막 비트가 1이면 cnt를 증가
x >>= 1; // x를 오른쪽으로 1비트 이동
}
return cnt;
}

 

다른 버젼

int BitCnt(int x)
{
int cnt = 0; // 1의 개수를 세기 위한 변수
while(x)
{
if (x % 2 != 0){ // x를 2로 나눈 나머지가 1이면 (즉, x의 현재 비트가 1이면)
cnt++; // 1의 개수 증가
}
x /= 2;
}
return cnt;
}