(인터)알못인데 아무리 검색해도 배열로 된 트라이 코드가 잘 안 나와서 직접 짠 거 올려봅니다.
먼가 난잡한데 그래도 뿌듯해하며 업로드~~ (사실 문제 안 풀어서 글 쓸 게 없어서 이런 거라도 올림니다 ㅎㅅㅎ

itrie와 ilen, dtrie와 dlen 각각 insert_trie 및 find_trie의 매개변수...?입니당
문자열 매개변수로 주고받는거 잘 못해서 그냥 전역으로 짰... ㅌㅌ


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
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct trie{
    int Go[27];
    int output;
}trie_tree[6000001];
int tn=0//root = 0
 
string itrie; int ilen;
void insert_trie(int a,int s){//a
    if(s==ilen){
        trie_tree[a].output = 1;
        return;
    }
    if(trie_tree[a].Go[itrie[s]-'a']==0){
        trie_tree[a].Go[itrie[s]-'a'= ++tn; trie_tree[tn].output=0;
        insert_trie(tn,s+1);
    } else {
        insert_trie(trie_tree[a].Go[itrie[s]-'a'],s+1);
    }
    return;
}
 
string dtrie; int dlen;
int find_trie(int a,int s){//a에서 s번째 문자 찾기 
    if(s==dlen) return trie_tree[a].output;
    if(trie_tree[a].Go[dtrie[s]-'a']==0){
        return 0;
    } else {
        return find_trie(trie_tree[a].Go[dtrie[s]-'a'],s+1);
    }
}
 
int N,M,ans=0string ipt;
int main(){
    ios_base::sync_with_stdio(false); cin.tie(0);
    cin>>N>>M;
    trie_tree[0].output=0;
    for(int i=1;i<=N;i++){
        cin>>ipt;
        itrie=ipt; ilen=itrie.length();
        insert_trie(0,0);
    }
    for(int i=1;i<=M;i++){
        cin>>ipt;
        dtrie=ipt; dlen=dtrie.length();
        ans+=find_trie(0,0);
    }
    cout<<ans;
}
cs

현 문제입니다. (이 게시판은 불친절 모드 게시판입니다)


[Baekjoon Onine Judge]


#1406 에디터


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



Problem Solving Strategy


-현 문제입니다. 리스트 써도 되고, 스택 써도 됩니다.

알고리즘 문제라기보다 구현이 까다로운 문제라 머 드릴 말씀이 없네요ㅎㅎ..

전 리스트로 풀다가 머리쓰느라 고생했는데, 큐로 풀면 어떨지는 모르겠씁니당.

0.3초라 시간 최대한 단축하려고 구조체로 구현했습니다.


저는 함수 안 쓰고 풀었기 때문에 모르겠는데

list 라이브러리나, 함수는 O(1)이어도 호출 시간이 길어서 시간 초과 날 수도 있을 거에요.

(사실 시간복잡도 계산 안해봐서 몰라요 ㅋㅋ 될 수도 이써요... 여기는 불친절모드 설명 게시판이니까용)


전체 코드 보기


자열 입력받는 거를 잘 못해서, 입력 받는데만 1시간 쏟았네요 ㅂㄷㅂㄷ...

첨 알았는데 scanf가 for문 안에 들어가니까 난리나더라구요 ㅎㅎ(?);;

gets()로 편하게 받았는데, 해당 문법이 C++14에서 삭제되서, gets()를 쓰고 싶으시다면  C++11로 제출해야합니다^^;;


...입력을 예쁘게 못 받은 듯 싶습니다....한두개 더 줄일 수 있을거 같지만

더 이상 코드를 수정할 기력이 없기에 .... 총총/


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
#include<bits/stdc++.h>
using namespace std
struct st{int f,b;char c;}editor[600009];
char ipt[100004],im[4]; int N,i,cs,sz;
int main(){
    scanf("%s\n",&ipt);    scanf("%d\n",&N);
    int asdf=strlen(ipt);
    for(i=1;i<=asdf;i++)
        editor[i]=(st){i-1,i+1,ipt[i-1]};
    editor[0].f=-1, editor[0].b=1; editor[i-1].b=-1; cs=i-1; sz=i;
    for(i=0;i<N;i++){ gets(im);
        if(im[0]=='L'&&editor[cs].f!=-1) cs=editor[cs].f;
        if(im[0]=='D'&&editor[cs].b!=-1) cs=editor[cs].b;
        if(im[0]=='B'&&editor[cs].f!=-1){
            cs=editor[cs].f;
            editor[cs].b=editor[editor[cs].b].b;
            editor[editor[cs].b].f=cs;
        }
        if(im[0]=='P'){
            editor[sz]=(st){cs,editor[cs].b,im[2]};
            editor[editor[cs].b].f=sz;
            editor[cs].b=sz;
            cs=editor[cs].b;
            sz++;
        }
    }
    i=cs; while(editor[i].f!=-1) i=editor[i].f; i=editor[i].b; 
    while(editor[i].b!=0){
        printf("%c",editor[i].c);
        i=editor[i].b;
    }
}
cs




'Algorithm > BOJ 문제풀이' 카테고리의 다른 글

[BOJ #2594] 놀이공원  (0) 2018.02.14
[BOJ #2613] 숫자구슬  (4) 2018.02.13
[BOJ #2610] 회의준비  (0) 2018.02.12

Educational Codeforces Round 49(Rated for Div.2) #C Minimum Value Rectangle 문제풀이입니다.
문제링크입니다.

http://codeforces.com/contest/1027/problem/C



Problem Solving Strategy


수학 문제입니다.
문자로 나타내어 식을 열심히 변형하면 결론은 a/b+b/a가 최소가 될 때 각각의 a, b를 구하는 문제와 동치입니다.
그래프를 그려보면, 사실 a, b각각의 값이 중요한게 아니고, 비율이 중요하죠.
b>a라고 했을 때 a/b가 1에 가까울수록 a/b+b/a가 최소가 되겠죠.



딩 전략



n이 10^6이라는 좀 큰 범위긴 하다만,
사실 an의 범위 해당하는 1부터 10^4까지의 숫자가 2번 나타나는지 4번 나타나는지가 중요합니다.
따라서 배열 크기는 10^4로 잡아줍니다.
입력받으면서 1~10000까지의 숫자가 각각 몇 번 나타나는지 기록하는데,
2번 나타날 때거나 4번 나타날 때, b라는 새로운 배열을 만들어서, 기록합니다.
4번 이상 나타난 수는 두 번 기록되고, 2-3회 등장한 수는 한 번 기록되겠죠.
b라는 배열을 정렬합니다. 왜? 비율이 최소가 되는게 궁금하니까, 인접해있는 수만 비교하면 됩니다.


예를 들어 1, 2, 8, 11 세 숫자 중 비율이 최소가 되는 두 수를 고르려면
1과 2 / 2와 8 / 8과 11 이 세 경우만 비교하면 되겠죠?


열심히 비교해서 최소가 되는 경우 체크한 뒤, 나중에 출력합니다.





리는 경우


간 초과 나는 경우에 대해 생각해보자면, (사실 제가 걸린 거)

코딩 편하게 하려고
b배열을 잡지 않고, 그냥 a배열을 훑으면서 풀려고 하다가,,,
n=6으로 T가 왕창 많이 들어왔을 경우 O(10000*T)>2~3초로 가볍게 넘어가버렸습니다...;;;


전체 코드 보기


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
#include<bits/stdc++.h>
using namespace std;
//a는 입력배열, b는 두 번 이상 나타나는 수들 목록 
int T,n,a[10004],b[10004],ipt,take1,take2,bsz; double ans;
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        keep=0, ans=0, bsz=0for(int i=0;i<=10002;i++) a[i]=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&ipt);
            a[ipt]++;
            if(a[ipt]==2||a[ipt]==4) b[bsz]=ipt, bsz++;
        }
        sort(b,b+bsz);
        for(int i=1;i<bsz;i++){
            if(ans<(double)b[i-1]/(double)b[i]){
                ans=(double)b[i-1]/(double)b[i];
                take1=b[i-1]; take2=b[i];
            }
        }
        printf("%d %d %d %d\n",take1,take1,take2,take2);
    }
}
 
cs



오늘의 문제는 2005년도 KOI 시.도 지역본선 2번인 [놀이공원]이에요.

#1931 회의실배정과 비슷하게 시작시간만을 보며 정렬한 뒤(회의실배정은 종료시간으로 정렬하죠 ㅎㅎ) 앞에서부터 탐색하며 풀이해도 풀리지만, 그러한 풀이는 이미 친절하게 포스팅 되어있어서, 저는 다른 방식으로 풀이해보았어요.


라인 스위핑의 기초 중의 기초 형태인데

#10714 JOI 2015년도 1번 기차여행 역시 본 풀이에서 사용한 기법을 이용하여 간단히 풀려요.


[Baekjoon Onine Judge]


#2594 놀이공원


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


2005 한국정보올림피아드 시.도지역본선 고등부 2번


Problem Solving Strategy


나라도  놀이기구가 운행 중이면, 철수와 영희는 데이트를 하지 못합니다.

반대로 말해, 우리가 확인해야하는 것은 '모든 놀이기구가 정지해있는가'에 대한 여부만 확인하면 됩니다.

지금 특정한 어느 놀이기구가 운행중인지는 궁금하지 않습니다.


문제 해결 아이디어는 간단합니다.

어떤 놀이기구의 운행 시작시간은 종료시간보다 반드시 앞서지요.

시간 순서대로 탐색하며 어떤 놀이기구의 운행이 시작할 때 +1을 하고 종료할 때 -1을 계산해주면, 그 순간에 몇 대의 놀이기구가 운영중인지를 알 수 있으며, 변수가 0이 될 경우에는 모든 놀이기구가 정지한 것입니다.


일단 입력을 꼼꼼하게 받아봅시다.

1.입력은 분 단위로 받아줍니다.

분 단위 출력만 하면 되므로 이 편이 뒤에서 변수를 다룰 때 코딩이 편하므로 당연하겠지요.

운행 10분전부터 10분 후까지도 철수와 영희는 만나지 못하므로, 해당 시간 역시 고려하여 받아줍시다.


1
2
3
4
5
for(int i=0;i<N;i++){
    scanf("%d %d",&input_start,&input_finish);
    start[i]=(input_start/100)*60+(input_start%100)-10;
    finish[i]=(input_finish/100)*60+(input_finish%100)+10;
}
cs


2. 시작시간과 종료시간을 각각 오름차순으로 정렬합니다.

정렬하며 어느 놀이기구의 시작시간과 종료시간을 매칭시킬 정보는 잃지만, 저희는 단지 어느 순간에 놀이기구가 시작하거나 종료했는지만 궁금하므로, 편하게 따로 정렬합시다.


1
2
sort(start,start+N);
sort(finish,finish+N);
cs


3. 시간 순서대로 탐색하며 시작과 종료의 개수를 카운팅합니다.

시간 순서대로 탐색하며 어떤 놀이기구의 운행이 시작할 때 +1을 하고 종료할 때 -1을 계산해주면, 그 순간에 몇 대의 놀이기구가 운영중인지를 알 수 있으며, 변수가 0이 될 경우에는 모든 놀이기구가 정지한 것입니다.


위에서 언급했던 대로입니다.
합병 정렬 (merge sort) 코드를 짤 때 처럼 start(시작 시간을 저장한 배열)과 finish(종료 시간을 저장한 배열)을 시간순으로 쭈욱 훑으며 코딩합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int s=0,f=0,MAX=0,active=0,start_break=600;
for(int i=0;i<(N*2);i++){
    if(start[s]<finish[f] && s!=N){//어떤 놀이기구의 운행이 시작함 
        active++;
        if(active==1 && MAX<(start[s]-start_break)){
            MAX=start[s]-start_break;
        }
        s++;
    }
    else{//어떤 놀이기구의 운행이 끝남
        active--;
        if(active==0){
            start_break=finish[f];
        } 
        f++;
    }
cs



리기 쉬운 부분


저는 22시를 분으로 변환하다가 13200이라 계산해서 제출 횟수를 상당히 낭비했지만... ㅋ...

코딩만 꼼꼼히 한다면 거의 없습니다.

4. 극단 값을 계산할 때 음수가 발생하지 않을까

입력을 받을 때 편하게 무차별적으로 10을 가감하고 받았는데 걱정할 법도 하지만 3번 질문의 코드처럼 MAX를 0이로 선언하고 항상 비교 후 갱신이 일어나도록 하면 걱정하는 일은 잃어나지 않음이 증명됩니다.


마지막으로 하루 일과를 시작하는 시간과 끝내는 시간을 고려하여 코딩을 마무리해줍니다.


전체 코드 보기


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
#include<cstdio>
#include<algorithm>
using namespace std;
int N,start[55],finish[55];
int main(void){
    scanf("%d",&N);
    int input_start,input_finish;
    for(int i=0;i<N;i++){
        scanf("%d %d",&input_start,&input_finish);
        start[i]=(input_start/100)*60+(input_start%100)-10;
        finish[i]=(input_finish/100)*60+(input_finish%100)+10;
    }
    sort(start,start+N);
    sort(finish,finish+N);
    int s=0,f=0,MAX=0,active=0,start_break=600;
    for(int i=0;i<(N*2);i++){
        if(start[s]<finish[f] && s!=N){//어떤 놀이기구의 운행이 시작함 
            active++;
            if(active==1 && MAX<(start[s]-start_break)){
                MAX=start[s]-start_break;
            }
            s++;
        }
        else{//어떤 놀이기구의 운행이 끝남
            active--;
            if(active==0){
                start_break=finish[f];
            } 
            f++;
        }
    } 
    /*마지막 놀이기구의 운행종류부터 일과를 마치는 시각까지*/
    if(MAX<(1320-start_break)){
        MAX=1320-start_break;
    }
    printf("%d",MAX);
}
cs


블로그에 공개를 하기 위해 코드가 많이 얌전해졌는데, 보통 굉장히 지저분하게 코딩을 해왔어서 그 습관이 여기저기 들어 있을 거 같아 피드백은 언제나 환영해요 *^~^*

'Algorithm > BOJ 문제풀이' 카테고리의 다른 글

[BOJ #1406] 에디터  (0) 2019.03.26
[BOJ #2613] 숫자구슬  (4) 2018.02.13
[BOJ #2610] 회의준비  (0) 2018.02.12

숫자구슬은 Parametric Search 를 알고 계셨다면 쉽게 풀으셨을겁니다. 이분 탐색을 이용하여 결정 문제를 해결하는 기법이에요.



[Baekjoon Onine Judge]


#2613 숫자구슬


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


2004 한국정보올림피아드 시.도지역본선 고등부 4번


Problem Solving Strategy


Parametric Search에 대해 알고 있거나, 이분탐색이나 나무자르기 같은 문제를 풀어보았으면 바로 떠오를 것입니다. ^=^

어쨌든 Parametric Search로 문제를 풀어봅시다.

1. 무엇을 이분탐색할 것인가?

범위로 주어진 것이 정답의 범위밖에 없으니까 정답의 범위를 이분탐색 해봅시다.

N은 300이하이고, 구슬의 숫자는 100이하이므로 정답의 범위는 30000이하이겠죠?

left는 1로 right는 30000으로 잡아줍시다.


1
int left=1,right=(100*N);
cs



2. 어떻게 판단할 것인가?

어떨 때 왼쪽으로 가고, 어떨 때 오른쪽으로 갈까요?

보통 문제의 조건에서 판단의 기준이 찾아져요.

이 문제에서 수치화된 조건은 그룹의 개수, 정답인 그룹의 구슬의 개수가 있네요.

아무래도 전자가 끌리죠?


답(mid)이 정해지면, 최소 그룹의 개수도 정해집니다.

How?

처음 구슬부터 시작해서 구슬의 합이 mid를 넘지 않을 때까지 한 그룹으로 묶어주면 되기 때문입니다.


1
2
3
4
5
6
7
for(int i=0;i<N;i++){
    sum+=marble[i];
    if(sum>mid){
        countGroup++;
        sum=marble[i];
    }
}
cs


그러면 구슬의 합이 mid를 넘지 않는 경우 그룹의 최대 개수가 정해집니다.

그룹의 최소 개수가 M보다 크면 정답이 아니죠? 오른쪽을 탐색해나갑니다.

작으면 그룹을 분할하여 M개가 될 수도 있으니, 일단 기존의 answer과 비교하여 mid가 더 작을 경우 answer를 mid로 바꾸고 왼쪽을 탐색해나갑니다.


1
2
3
4
5
if(countGroup>M) left=(mid+1);
else{
    right=(mid-1);
    if(mid<ans) ans=mid;
}
cs



리기 쉬운 부분


사실 이 부분은 어떻게 풀었고, 어떻게 구현했는가에 따라서 각자 다른 오답노트를 작성하게 되겠지만, 제 경우입니다.

3. 만약에, 구슬이 mid보다 클 경우에는?

저격데이터라 부르기도 민망한 케이스죠. 제가 걸렸으니까 포스팅에 넣어봅니다ㅋㅋㅋ

이경우 탐색은 무조건 오른쪽이니까, 아까 2번 과정의 첫 번째 코드에 있는 for문 안에 다음과 같은 if문을 넣어 해당 케이스를 표기합니다.


1
2
3
4
5
if(marble[i]>mid){
    left=mid+1;
    boolean=0;
    break;
}
cs


그리고 두 번째 코드에서 if(오른쪽을 탐색할 것인가)에 오른쪽을 탐색한다!라고 명령합니다.


1
if(countGroup>|| boolean==0) (left=mid+1);
cs


뭐 다양한 해결방법이 있겠지만 저는 위처럼 해결했습니다.


그리고...

꽤나 (제가) 찾기 어려웠던 케이스인 아래 상황을 소개합니다!


4. 한 그룹에는 하나 이상의 구슬이 있어야 한다

이렇게 들으니 감이 잘 안 올거에요. 이게 왜 저격 데이터야? 묻는 사람이 있을 겁니다.


보통 코드 구현 과정에서 각 그룹을 구성하는 구슬의 개수를 출력할 때, 이진탐색을 도는 과정에서 저장을 하거나, 이진탐색에서의 코드를 아래에 복붙한 뒤, mid만 answer로 바꾸어서 출력을 합니다.

그리고 맞았습니다가 뜨기를 기도하며 제출을 하지만

결과는 틀렸습니다.

네. 저도 그랬습니다 ㅋㅋㅋ캬캬ㅏ


문제를 잘 읽어보면 최대값과 각 그룹을 구성하는 구슬의 개수를 출력해야합니다.


현재 mid가 2일 때 


4 2

1 1 2 1 이라고 입력해봅시다.


그러면 그룹 분류가 다음과 같이 됩니다.

(1,1) (2) (1)

그럼 그룹의 구슬 개수를 출력이 다음처럼 나오겠죠?

2 1 1

넵. 틀렸습니다.


결과를 출력하기 전에

세어진 그룹의 개수와 M을 비교한 뒤

부족한 그룹의 개수만큼

중간에 구슬의 개수가 2개 이상인 그룹을 분할해서 해결해줍시다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int num=0,sum=0;
for(int i=0;i<N;i++){
    sum+=marble[i];
    num++;
    if(sum>ans){
        sum=marble[i];
        answer[ansSize]=num-1;
        ansSize++;
        num=1;
    }
}
answer[ansSize]=num;
int difference=(M-ansSize); //M과 ansSize의 차이를 계산한다.
for(int i=1;i<=ansSize;i++){
    if(answer[i]==1printf("%d ",answer[i]);
    else{
        while(answer[i]>=2 && difference>=1){
            printf("1 ");
            answer[i]--; difference--;
        }
        printf("%d ",answer[i]);
    }
}
cs



전체 코드 보기


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
52
53
54
55
#include<cstdio>
int N,M,marble[302];
int answer[301],ansSize=1;
int main(void){
    scanf("%d %d",&N,&M);
    for(int i=0;i<N;i++scanf("%d",&marble[i]);
    int left=1,right=(100*N);
    int ans=999;
    while(left<=right){
        int mid=(left+right)/2;
        int sum=0,countGroup=1;
        bool boolean=1;
        for(int i=0;i<N;i++){
            if(marble[i]>mid){
                left=mid+1;
                boolean=0;
                break;
            }
            sum+=marble[i];
            if(sum>mid){
                countGroup++;
                sum=marble[i];
            }
        }
        if(countGroup>|| boolean==0) (left=mid+1);
        else{
            right=(mid-1);
            if(mid<ans) ans=mid;
        }
    }
    printf("%d\n",ans);
    int num=0,sum=0;
    for(int i=0;i<N;i++){
        sum+=marble[i];
        num++;
        if(sum>ans){
            sum=marble[i];
            answer[ansSize]=num-1;
            ansSize++;
            num=1;
        }
    }
    answer[ansSize]=num;
    int difference=(M-ansSize);
    for(int i=1;i<=ansSize;i++){
        if(answer[i]==1printf("%d ",answer[i]);
        else{
            while(answer[i]>=2 && difference>=1){
                printf("1 ");
                answer[i]--; difference--;
            }
            printf("%d ",answer[i]);
        }
    }
}

cs



네엡! Parametric Search가 이런 거에요 *-*

사실 Parametric Search라는 용어보다는 관련문제인 #2805 나무자르기가 더 유명한데, 이 문제도 풀어보면 좋아요.


지역본선은 정말 문제를 보고 기초 알고리즘을 떠올릴 수 있으면 풀 수 있는 문제가 대부분이에요 

그래도 꼼꼼하지 않으면, 저처럼 몇 번씩 틀립니다ㅠ-ㅠ

'Algorithm > BOJ 문제풀이' 카테고리의 다른 글

[BOJ #1406] 에디터  (0) 2019.03.26
[BOJ #2594] 놀이공원  (0) 2018.02.14
[BOJ #2610] 회의준비  (0) 2018.02.12

시.도지역본선 초반 번호대의 문제다운 난이도로, Floyd-Warshall Algorithm (플로이드 와샬)을 이용해, 간단히 해결되는 문제입니다.



[Baekjoon Onine Judge]


#2610 회의준비


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


2004 한국정보올림피아드 시.도지역본선 중등부 3번

2004 한국정보올림피아드 시.도지역본선 고등부 3번


Problem Solving Strategy


음과 같은 세 부분으로 나누어 생각을 해야지! 라는 생각이 떠오를 것입니다.

1. 모든 사람에 대해 플로이드 와샬 알고리즘을 돌린다.

2. 조건에 맞게 위원회를 구성한다.

3. 위원회의 대표를 찾는다.


1. 모든 사람에 대해 플로이드 와샬 알고리즘을 돌린다.

위원회의 대표를 찾는 과정에서, 플루이드 와샬 알고리즘이 필요하다는 것은 깨달았을 것입니다.

각각의 위원회에 대해 돌려도 되지만 코드가 불필요하게 길어지며, 모든 사람이 같은 위원회에 속하는 경우의 수도 존재하므로

처음에 그냥 모든 정점을 집어넣고 돌립니다.


1
2
3
4
for(int k=1;k<=N;k++)
    for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)
            if(i!=&& dist[i][j]>dist[i][k]+dist[k][j]) dist[i][j]=dist[i][k]+dist[k][j];
cs


2. 조건에 맞게 위원회를 구성한다.

3. 위원회의 대표를 찾는다.

굳이 각 위원회의 정보를 저장할 필요가 없으므로,  imsi로 그룹원을 저장하는 배열을 만들고 대표를 찾은 뒤, 각 그룹의 대표만 저장해도 됩니다. 본인은 반복문 탈출 조건을 N명의 사람을 모두 방문했을 때로 했습니다.


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
vSize=0; aSize=0;
while(vSize<N){ //방문한 사람 수가 N보다 작은 동안 반복문을 돕니다.
//임시 위원회를 구하는 과정입니다.
    emptyImsi();
    for(int i=1;i<=N;i++){
        if(imsisize==0 && visited[i]==0){ //임시 위원회의 한 사람을 구합니다.
            visited[i]=1//방문자 처리
            imsisize++; vSize++;
            imsi[imsisize]=i;
            e=i;
        }
        if(imsisize!=0 && dist[e][i]!=INF){ //임시 위원회의 나머지 그룹원을 채워줍니다.
            visited[i]=1;
            imsisize++; vSize++;
            imsi[imsisize]=i;
        }
    }
 
//위원회의 대표를 찾는 과정입니다.
    s=1;//s는 일단 위원회의 1번을 대표라 가정합니다.
    int pe=INF;
    for(int i=1;i<=imsisize;i++)
    {    
        e=0;
        for(int j=1;j<=imsisize;j++)
        {
            if(e<=dist[imsi[i]][imsi[j]] && i!=j){
                e=dist[imsi[i]][imsi[j]];
            }
        }
        if(pe>=e){
            s=i;
            pe=e;
        }
    }
    aSize++//출력할 답의 크기를 저장합니다.
    ans[aSize]=imsi[s]; //출력에 필요한 답만 저장해둡니다.
}
cs


전체 코드 보기


블로그에 정리할 생각을 하지 않고 짰던 거라 변수명과 코드가 조금 지저분..해요 ㅠ-ㅠ


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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include<cstdio>
#include<algorithm>
#define INF 987654321
using namespace std;
 
int N, dist[101][101];
int imsi[101],imsisize,visited[101],vSize;
int M,s,e;
int ans[101],aSize;
 
void emptyImsi(){
    for(int i=1;i<=N;i++) imsi[i]=0;
    imsisize=0;
}
 
int main(void){
    imsisize=0;
    scanf("%d",&N);
    scanf("%d",&M);
    for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)
            dist[i][j]=INF;
    for(int i=1;i<=M;i++){
        scanf("%d %d",&s,&e);
        dist[s][e]=1; dist[e][s]=1;
    }
 
    //fw algorithm//
    for(int k=1;k<=N;k++)
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
            if(i!=&& dist[i][j]>dist[i][k]+dist[k][j]) dist[i][j]=dist[i][k]+dist[k][j];
 
    vSize=0; aSize=0;
    while(vSize<N){
    //임시 부분집합을 구하고
        emptyImsi();
        for(int i=1;i<=N;i++){
            if(imsisize!=0 && dist[e][i]!=INF){
                visited[i]=1;
                imsisize++; vSize++;
                imsi[imsisize]=i;
            }
            if(imsisize==0 && visited[i]==0) {
                visited[i]=1;
                imsisize++; vSize++;
                imsi[imsisize]=i;
                e=i;
            }
        }
        
    //부분그룹의 대표를 찾는다.
        s=1;//s는 일단 부분그룹 1번이 대표!
        int pe=INF;
        for(int i=1;i<=imsisize;i++)
        {    
            e=0//s는 임시 그룹 1번 여기서부터 e=MAX
            for(int j=1;j<=imsisize;j++)
            {
                if(e<=dist[imsi[i]][imsi[j]] && i!=j){
                    e=dist[imsi[i]][imsi[j]];
                }
            }
            if(pe>=e){
                s=i;
                pe=e;
            }
        }
        aSize++;
        ans[aSize]=imsi[s];
    }
    sort(ans+1,ans+1+aSize);
    printf("%d\n",aSize);
    for(int i=1;i<=aSize;i++)
        printf("%d\n",ans[i]);
    return 0;
}




'Algorithm > BOJ 문제풀이' 카테고리의 다른 글

[BOJ #1406] 에디터  (0) 2019.03.26
[BOJ #2594] 놀이공원  (0) 2018.02.14
[BOJ #2613] 숫자구슬  (4) 2018.02.13

+ Recent posts