forum

프로그래밍 thread

posted
Total Posts
36
show more
Topic Starter
A BCDe

UnLock- wrote:

형님들 제가 과제가 막혀서 그런데 좀 도와주세용 ㅠㅠ

문제
산타의 양말 찾기
50개의 선물 상자 중에 한 개의 상자에는 산타의 양말이 들어 있다. 다음의 조건에 맞는 양말이 들어있는 상자를 찾는 프로그램을 작성하시오.
1. 상자는 배열을 이용하여 구현, 선물 상자의 무게는 10 양말 상자의 무
게는 1로 가정
2. 상자를 여는 횟수는 1번으로 제한 (배열을 탐색하여 1인 것을 찾는 방
법은 불가)
3. 상자들의 무게를 비교하여 범위를 제한하는 함수는 재귀 함수로 작성(
비교하는 횟수는 6번 이하)

일단 조교님 힌트로는 이진 탐색이랑 비슷한 방법으로 하면 된다는데

도오오오오오오저히 답이 안나옵니다 ㅠㅠ

일단 지금까지 짠 코드는 이따 집가서 보여드릴게용 ㅠㅠ
답이 좀 늦은것인지도 모르겠는데요

저는 이 상자들을 3개로 나눠봤습니다.

그러니까, 50개의 상자면 17,17, 16 이렇게 세 더미로 최대한 균등하게 나눠보자는 것입니다.

그럼 첫번째 17개 상자들과 두번째 17개 상자들을 비교하면

1) 무게가 같다
2) 첫번째가 무겁다
3) 두번째가 무겁다

이렇게 세가지가 있겠죠.

1)의 경우에는 16개짜리 더미에 양말이 들어있는 것이겠죠.
2)의 경우에는 첫번째 17개 상자들 중 양말이 있겠죠.
3)의 경우에는 두번째 17개 상자들 중 양말이 있겠죠.

17, 17, 16이 아니더라도 16, 16, 18도 되겠죠.

이런 식으로 범위를 줄여나갈 수 있습니다.

이러면 최대 4번이면 양말을 찾을 수 있습니다.

c++ 코드입니다.

#include <stdio.h>
#include <random> // 랜덤을 위한 헤더
#include <time.h> // 랜덤을 위한 헤더
#pragma warning(disable : 4996) // visual studio 2013 또는 그 이상을 사용하지 않는다면 필요없음

#define NUM 50

int box[NUM];

void SetSock() // 상자 안에 양말 넣기
{
srand((unsigned)time(NULL));
int a = rand() % NUM;
printf("%d\n", a); // 확인용 출력
for (int i = 0; i < NUM; i++)
{
if (i == a)
{
box[i] = 11; // 양말이 있는 상자
}
else
{
box[i] = 10; // 양말이 없는 상자
}
}
}

int BoxSum(int a, int b) // 상자들의 무게의 합
{
int w = 0;
for (int i = a; i < b; i++)
{
w += box[i];
}
return w;
}

void FindSock(int a, int b)
{
int n = b - a; // 개수
int delta = n / 3 + 1; // 한 묶음의 상자 개수

int boxSum1 = BoxSum(a, a + delta);
int boxSum2 = BoxSum(a + delta, a + 2 * delta);

if (n == 1)
{
printf("ans : %d\n", a); // 답 출력
return;
}

if (boxSum1 == boxSum2) // 첫번째 상자들과 두번째 상자들의 무게가 같다면
{
FindSock(a + 2 * delta, b);
return;
}
else if (boxSum1 > boxSum2) // 첫번째 상자들이 무겁다면
{
FindSock(a, a + delta);
return;
}
else // 두번째 상자들이 무겁다면
{
FindSock(a + delta, a + 2 * delta);
return;
}
}

int main()
{
SetSock();
FindSock(0, NUM);
}
Sylphi
그러고보니 제쪽이 문제 자체를 잘못 이해하고 답변했네요. 저경우에는 제가 답변한대로는 결과가 안나옵니다.
(25, 25같이 같은 숫자의 경우에는 차이가 나겠지만, 12, 13같은 경우에는 무게가 121, 130 혹은 120, 131가 나와서 갯수가 적은쪽이 무조건 가벼움)

A BCDe님이 말하신대로 하면 결과가 나올겁니다.

SPOILER
양말이 들어있는 상자가 어느쪽에 있냐에 따라서 아래와 같이 되니

171, 170, 160
170, 171, 160
170, 170, 161

첫번째와 두번째 묶음을 비교해서 같다면 세번째 묶음에 양말이 있는 상자가 있는거고
나머지의 경우에는 더 무게가 많이 나가는쪽이 양말이 있는거라고 보면 되니까요

만약 11번째 상자에 양말이 있다는 전제하에 계산해보면 이런식으로 될겁니다.

17(171), 17(170), 16(160)
6(60), 6(61), 5(51)
3(20), 3(21), 0(30)
1(10), 1(11), 1(10)

도데체 왜 전 상자무게를 1로 보고 양말 무게로 10으로 본걸까요. (본격 상자보다 양말이 더 무거운 이상한 선물)
Kawashiro
결국 제출 못하고 0점 받았지맘 답변 감사합니다

다음엔 꼭 일찍 물어보는걸로....ㅠㅠ
Topic Starter
A BCDe
살아나라 스레드여

그렇다고 아무것도 안 올릴 수는 없으니

quick sort in c++
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}

void quick(int left, int right, int* arr)
{
int pivot = left;
int i = left + 1;
int j = right;
if(left < right)
{
while(i <= right)
{
if(arr[i] < arr[pivot])
swap(arr[i], arr[++j]);
i++;
}
swap(arr[left], arr[j]);
pivot = j;
quick(left, pivot - 1, arr);
quick(pivot + 1, right, arr);
}
}
Doyak
ACM-ICPC 예선 아마 탈락인 거 같네요. 89등인데 학교 내 7등이라 여기까지 안 뽑아줄 듯합니다 ㅠㅠ

그러니 백준 열심히 합시다
Topic Starter
A BCDe
아쉽네요 ㅠㅠ

그나저나 여기서 acmicpc를 보니 정말 반갑습니다!

Doyak wrote:

그러니 백준 열심히 합시다
Doyak
문제 난이도가 딱 4문제까지는 쉽거나 평이하고, 그 위로는 갑자기 헬이었던 느낌이네요. 4문제 푼 팀이 150팀 가까이 되는데 한 팀을 제외하곤 모두 푼 문제 종류가 똑같고, 5개 이상 푼 팀들이 추가로 푼 문제들은 제법 다양하게 분포한 걸 보면요. 작년에 7문제 이상 푼 팀 수랑 이번에 6문제 이상 푼 팀 수가 비슷하기도 하고요.
Topic Starter
A BCDe
그래도 J는 그 중에서도 어려웠답니다
이번에는 5문제 이상 풀면 충분히 잘한 팀이죠.
저같은 경우는 팀에서 4문제를 풀고 G를 손댔는데 DP로 접근이 안 되서 시간 다 날렸네요.
(나중에 지인한테 풀이를 들어보니 DP라고는 하던데.)
Doyak
G번 팀원이 2차원 dp로 풀고 있었는데 제출했더니 시간초과가 났다고 하더라고요. 정답은 자신 없어도 시간은 괜찮을 거라고 생각하셨다는데 안타깝던 ㅠㅠ

전 괜히 C번 팠다가 시간만 날렸고, L번이랑 F번도 꽤 들여다봤는데 잘 안 되더라고요.
Taeyang
잘 안풀렷던 문자열 문제 2개만 질문 해보겠습니다.!

문제 1
제가짠 코드
#include <stdio.h>
#include <string.h>

int main() {
char word[50][101];
int i,cnt=0;
while(1){
gets(word[cnt]);
cnt++;
if(word[cnt][0]=='0') break;
}
printf("%d\n",cnt);
for(i=0;i<cnt;i++){
if(i%2==0){
puts(word[i]);
}
}
return 0;
}
이건 if절쪽 if(word[cnt][0]=='0') break; 이놈이 잘못된거 같은데 어떻게 맞게 고쳐야 할지 모르겠음

문제2

 
#include <stdio.h>
#include <string.h>

int main()
{
char st[101];
int i,len;
while(1){
gets(st);

if(st[0]=='E'&&st[1]=='N'&&st[2]=='D') break;

len=strlen(st);
for(i=len;i>=0;i--){
printf("%c",st[i]);
}
}
return 0;
}

이것도 END 입력하면 끝내야하는데 안끝남...
Doyak
1. word[cnt]에 문자열을 입력받았는데 그 즉시 cnt를 증가시켰으니 if문에서 검사되는 word[cnt][0]은 입력받을 때보다 1 큰 cnt로 검사하는 거니, 절대로 걸릴 리가 없죠.

2. 잘 끝나는데요? 그보다 len부터 시작하면 안 되고 len - 1부터 시작해야 원하는 결과를 얻으실 수 있을 거에요. len번째에는 널 문자가 저장되어 있으니까요.
Topic Starter
A BCDe
히익 한발 늦었다

참고로 덧붙이자면 저는 문자열 입력을 받을 때는 scanf나 gets보다 fgets를 '주로' 사용합니다.

아니면 아얘 cin을 쓰거나..
Doyak
C++은 C++14부터 gets 함수 자체를 아예 지원을 안 합니다. 사실, 안전성 부분에 있어서 gets, scanf, strcpy 같이 위험한 함수들은 C에서도 점차 비추하는 추세죠. (VS에서 따로 설정을 안 하면 에러를 띄우는 이유)

그리고 cin이 좋기는 한데 알고리즘 문제에 있어선 scanf보다 느린 게 ㅠㅠ
Topic Starter
A BCDe
cin은 std::ios::sync_with_stdio(false)를 써주면 scanf()보다 더 빠른 성능을 보여줍니다!
Taeyang
1.우왕 cnt 랑 if 있는곳 바꾸니깐 해결됨....
2.
#include <stdio.h>
#include <string.h>

int main()
{
char st[101];
int i,len;
while(1){
scanf("%s",st);
if(st[0]=='E'&&st[1]=='N'&&st[2]=='D'&&st[3]=='\0') break;
len=strlen(st);
for(i=len-1;i>=0;i--){
printf("%c",st[i]);
}
printf("\n");
}
return 0;
}

이랬더니 해결됨 gets()를 쓰면 이상하게 한칸 띄워진 다음에 출력되네영
Taeyang
책이 한 7~8년 된 책이라 그런지... scanf_s은 저기서 먹히지도 않음 ㅠㅠ
이제 포인터랑 파일 입출력 파트만 끝내면 끝난다\o/~

지금 포인터 중간쯤 풀고있는데 이거 어따가 활용하나요 (책에는 안나와있음)
인터넷에 나온 설명 보긴 봤는데
http://blog.naver.com/qorckddls010/220981696090
http://cafe.naver.com/cafec/366826 이런거...
구체적으로 어쩔때 쓰고 활용해야 될질 모르겠습니다.
Doyak
엇 그걸 해도 cin은 scanf보다 느리다고 들었는데 잘못된 정보려나요?
Topic Starter
A BCDe

Doyak wrote:

엇 그걸 해도 cin은 scanf보다 느리다고 들었는데 잘못된 정보려나요?
https://online.acmicpc.org/help/cpp
여기서는 이 방법을 소개하고 있고,
https://stackoverflow.com/questions/1042110/using-scanf-in-c-programs-is-faster-than-using-cin
여기서는 사용 예시를 보여주고 있습니다.

Taeyang wrote:

책이 한 7~8년 된 책이라 그런지... scanf_s은 저기서 먹히지도 않음 ㅠㅠ
visual studio 2013 이상을 사용하신다면 scanf_s를 사용해야겠지만(scanf를 사용하면 에러가 발생합니다), 다른 프로그램에서는 적용되지 않은 것으로 알고 있습니다.
물론 그것도 맨 위에 #pragma warning(disable : 4996)을 붙여주신다면 scanf를 사용할 수는 있지만요.

Taeyang wrote:

지금 포인터 중간쯤 풀고있는데 이거 어따가 활용하나요 (책에는 안나와있음)
처음 배울 때는 정말 불편한 것처럼 보이지만 잘 익힌다면 꽤나 유용한 도구로 쓰입니다.
그런데 솔직히 저도 이것이 어떤 곳에 활용되는지는 잘 모르니 조용히 있겠습니다.
Doyak
cin은 빠르군요. 예전에 똑같은 코드를 sync_with_stdio(false) + cout과 printf로 비교해봤을 때는 printf가 몇배는 빨라서, 그 이후로 아예 iostream을 던지고 cstdio만 썼는데 앞으로는 입력은 cin으로 받는 걸 고려해야겠네요.

그리고 사실 cin의 약점 중 하나가, 여러 개의 값을 저장하기 위해서 그 갯수만큼 호출이 되어야 한다는 것인데, 이것도 약간의 변수가 될 수 있을 듯합니다. 시스템 종류나 입력받는 것이 정수인지 문자인지 등에 따라서도 다를 것 같고요.
Topic Starter
A BCDe
그래도 진짜 속도를 따진다면 getchar가 최고죠 ㅎㅎ
불편해서 안 쓴다 뿐이지..
Sylphi

A BCDe wrote:

그래도 진짜 속도를 따진다면 getchar가 최고죠 ㅎㅎ
불편해서 안 쓴다 뿐이지..

ㅋㅋㅋㅋㅋ 그러고보니 그렇네요
Doyak
BOJ 같이 하실 분 구해요

그룹도 만들면 재미있을 텐데 사람이 있으면...

https://www.acmicpc.net/user/djm03178 입니다.
Topic Starter
A BCDe

Doyak wrote:

BOJ 같이 하실 분 구해요

그룹도 만들면 재미있을 텐데 사람이 있으면...

https://www.acmicpc.net/user/djm03178 입니다.
2/n
Doyak
예전에 그 cin이 느리다고 생각했던 이유 중 하나가... cin.tie(NULL); 을 하지 않은 상태에서 cout와 cin을 번갈아 쓸 경우 cin을 사용할 때마다 cout에 flush가 일어나서 매우 느렸던 일이 있었는데, 이걸 써주니 괜찮네요. 환경마다 다르긴 하겠지만 BOJ에서 정수 입력 기준으론 cin이 scanf보다 확실히 빠르게 나오네요.
Left
#offtopic 이 살며시 떠올라버리는건
Doyak

Left wrote:

#offtopic 이 살며시 떠올라버리는건

그래서 이제 장소를 아예 딴 서버로 옮겼죠
Please sign in to reply.

New reply