문제:

월드컵 축구의 응원을 위한 모임에서 회장을 선출하려고 한다. 이 모임은 만들어진지 얼마 되지 않았기 때문에 회원 사이에 서로 모르는 사람도 있지만, 몇 사람을 통하면 모두가 서로 알 수 있다. 각 회원은 다른 회원들과 가까운 정도에 따라 점수를 받게 된다.

예를 들어 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점이다. 어느 회원의 점수가 2점이면, 다른 모든 회원이 친구이거나 친구의 친구임을 말한다. 또한 어느 회원의 점수가 3점이면, 다른 모든 회원이 친구이거나, 친구의 친구이거나, 친구의 친구의 친구임을 말한다.

4점, 5점 등은 같은 방법으로 정해진다. 각 회원의 점수를 정할 때 주의할 점은 어떤 두 회원이 친구사이이면서 동시에 친구의 친구사이이면, 이 두사람은 친구사이라고 본다.

회장은 회원들 중에서 점수가 가장 작은 사람이 된다. 회장의 점수와 회장이 될 수 있는 모든 사람을 찾는 프로그램을 작성하시오.

입력:

입력의 첫째 줄에는 회원의 수가 있다. 단, 회원의 수는 50명을 넘지 않는다. 둘째 줄 이후로는 한 줄에 두 개의 회원번호가 있는데, 이것은 두 회원이 서로 친구임을 나타낸다. 회원번호는 1부터 회원의 수만큼 붙어 있다. 마지막 줄에는 -1이 두 개 들어있다.

출력:

첫째 줄에는 회장 후보의 점수와 후보의 수를 출력하고, 두 번째 줄에는 회장 후보를 오름차순으로 모두 출력한다.

풀이방법:

'친구사이'라는 용어가 애매하게 정의되어 있어서 헷갈릴 수 있지만 자신을 제외한 다른 모든 회원과 친구가 되기 위해 필요한 최대 거리를 의미한다. 즉 '친구의 친구의 친구'는 그 사람과 내가 알기 위해서 필요한 다리의 수와 같다.

따라서 이 문제를 플로이드-와샬문제로 생각하여 해결한다. 플로이드-와샬로 친구가 되기 위해 필요한 사람의 수들을 모두 구한 뒤, 각 사람마다 제일 큰 값이 그 회원의 점수가 된다.

회장이 될 수 있는 사람은 그 점수들 중 가장 작은 사람이여야 하기 때문에 그 점수들 중에 min을 찾은 후 그 점수를 가지고 있는 사람들을 출력한다.

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
= int(input())
INF = float('inf')
arr = [[INF for _ in range(N+1)] for _ in range(N+1)]
for i in range(1,N+1):
    arr[i][i] = 0
 
while True:
    a,b = map(int,input().split())
    if a==-1 and b==-1:
        break
    arr[a][b] = 1
    arr[b][a] = 1
    
for k in range(1,N+1):
    for i in range(1,N+1):
        for j in range(1,N+1):
            if arr[i][j] > arr[i][k] + arr[k][j]:
                arr[i][j] = arr[i][k] + arr[k][j]
score = []
for i in range(1,N+1):
    score.append(max(arr[i][1:]))
ans_score = min(score)
candiate_n = score.count(ans_score)
print(ans_score, candiate_n)
print(*[i+1 for i in range(N) if ans_score==score[i]])
cs

문제링크:

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

 

2660번: 회장뽑기

입력의 첫째 줄에는 회원의 수가 있다. 단, 회원의 수는 50명을 넘지 않는다. 둘째 줄 이후로는 한 줄에 두 개의 회원번호가 있는데, 이것은 두 회원이 서로 친구임을 나타낸다. 회원번호는 1부터

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2526. 싸이클  (0) 2022.02.14
[BOJ]2641. 다각형그리기  (0) 2022.02.11
[BOJ]10827. a^b  (0) 2022.02.09
[BOJ]2631. 줄세우기  (0) 2022.02.08
[BOJ] 9576. 책 나눠주기  (0) 2022.02.07

문제:

1번부터 N번까지 번호가 붙여져 있는 학생들에 대하여 두 학생끼리 키를 비교한 결과의 일부가 주어져 있다. 단, N명의 학생들의 키는 모두 다르다고 가정한다. 예를 들어, 6명의 학생들에 대하여 6번만 키를 비교하였고, 그 결과가 다음과 같다고 하자.

  • 1번 학생의 키 < 5번 학생의 키
  • 3번 학생의 키 < 4번 학생의 키
  • 5번 학생의 키 < 4번 학생의 키
  • 4번 학생의 키 < 2번 학생의 키
  • 4번 학생의 키 < 6번 학생의 키
  • 5번 학생의 키 < 2번 학생의 키

이 비교 결과로부터 모든 학생 중에서 키가 가장 작은 학생부터 자신이 몇 번째인지 알 수 있는 학생들도 있고 그렇지 못한 학생들도 있다는 사실을 아래처럼 그림을 그려 쉽게 확인할 수 있다. a번 학생의 키가 b번 학생의 키보다 작다면, a에서 b로 화살표를 그려서 표현하였다. 

1번은 5번보다 키가 작고, 5번은 4번보다 작기 때문에, 1번은 4번보다 작게 된다. 그러면 1번, 3번, 5번은 모두 4번보다 작게 된다. 또한 4번은 2번과 6번보다 작기 때문에, 4번 학생은 자기보다 작은 학생이 3명이 있고, 자기보다 큰 학생이 2명이 있게 되어 자신의 키가 몇 번째인지 정확히 알 수 있다. 그러나 4번을 제외한 학생들은 자신의 키가 몇 번째인지 알 수 없다.

학생들의 키를 비교한 결과가 주어질 때, 자신의 키가 몇 번째인지 알 수 있는 학생들이 모두 몇 명인지 계산하여 출력하는 프로그램을 작성하시오.

입력:

첫째 줄에 학생들의 수 N (2 ≤ N ≤ 500)과 두 학생 키를 비교한 횟수 M (0 ≤ M ≤ N(N-1)/2)이 주어진다. 다음 M개의 각 줄에는 두 학생의 키를 비교한 결과를 나타내는 두 양의 정수 a와 b가 주어진다. 이는 번호가 a인 학생이 번호가 b인 학생보다 키가 작은 것을 의미한다. 

출력:

자신이 키가 몇 번째인지 알 수 있는 학생이 모두 몇 명인지를 출력한다. 

풀이방법:

 자신을 기준으로 다른 사람에게 도달할 수 있다. 즉, 비교를 할 수 있는 사람이 몇명인지 확인하도록 한다. 자신보다 큰 사람과 자신보다 작은 사람이 N-1명이면 자신의 키가 몇 번째인지 알 수 있다.

 따라서 플로이드 와샬을 사용해서 이 문제를 풀도록 한다. 플로이드 와샬은 모든 꼭짓점 쌍 간의 최단 경로의 길이를 알 수 있는 알고리즘인데, 이 문제에 알맞게 몇명과 비교를 할 수 있는지 여부로 수정하여 문제를 해결하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
N, M = map(int,input().split())
graph = [[0 for _ in range(N)] for _ in range(N)]
for _ in range(M):
    a, b = map(int,input().split())
    graph[a-1][b-1= 1
 
for k in range(N):
    for i in range(N):
        for j in range(N):
            if graph[i][j] or (graph[i][k] and graph[k][j]):
                graph[i][j] = 1
                
answer = 0
for i in range(N):
    tmp = 0
    for j in range(N):
        tmp += graph[i][j] + graph[j][i]
    if tmp == N-1:
        answer+=1
print(answer)
cs

문제링크:

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

 

2458번: 키 순서

1번부터 N번까지 번호가 붙여져 있는 학생들에 대하여 두 학생끼리 키를 비교한 결과의 일부가 주어져 있다. 단, N명의 학생들의 키는 모두 다르다고 가정한다. 예를 들어, 6명의 학생들에 대하여

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ] 15683. 감시  (0) 2021.10.12
[BOJ] 14500. 테트로미노  (0) 2021.10.08
[BOJ] 21608. 상어 초등학교  (0) 2021.10.06
[BOJ] 10157. 자리배정  (0) 2021.10.05
[BOJ] 1019. 책 페이지  (0) 2021.10.01

문제:

예은이는 요즘 가장 인기가 있는 게임 서강그라운드를 즐기고 있다. 서강그라운드는 여러 지역중 하나의 지역에 낙하산을 타고 낙하하여, 그 지역에 떨어져 있는 아이템들을 이용해 서바이벌을 하는 게임이다. 서강그라운드에서 1등을 하면 보상으로 치킨을 주는데, 예은이는 단 한번도 치킨을 먹을 수가 없었다. 자신이 치킨을 못 먹는 이유는 실력 때문이 아니라 아이템 운이 없어서라고 생각한 예은이는 낙하산에서 떨어질 때 각 지역에 아이템 들이 몇 개 있는지 알려주는 프로그램을 개발을 하였지만 어디로 낙하해야 자신의 수색 범위 내에서 가장 많은 아이템을 얻을 수 있는지 알 수 없었다.

각 지역은 일정한 길이 l (1 ≤ l ≤ 15)의 길로 다른 지역과 연결되어 있고 이 길은 양방향 통행이 가능하다. 예은이는 낙하한 지역을 중심으로 거리가 수색 범위 m (1 ≤ m ≤ 15) 이내의 모든 지역의 아이템을 습득 가능하다고 할 때, 예은이가 얻을 수 있는 아이템의 최대 개수를 알려주자.

주어진 필드가 위의 그림과 같고, 예은이의 수색범위가 4라고 하자. ( 원 밖의 숫자는 지역 번호, 안의 숫자는 아이템 수, 선 위의 숫자는 거리를 의미한다) 예은이가 2번 지역에 떨어지게 되면 1번,2번(자기 지역), 3번, 5번 지역에 도달할 수 있다. (4번 지역의 경우 가는 거리가 3 + 5 = 8 > 4(수색범위) 이므로 4번 지역의 아이템을 얻을 수 없다.) 이렇게 되면 예은이는 23개의 아이템을 얻을 수 있고, 이는 위의 필드에서 예은이가 얻을 수 있는 아이템의 최대 개수이다.

입력:

첫째 줄에는 지역의 개수 n (1 ≤ n ≤ 100)과 예은이의 수색범위 m (1 ≤ m ≤ 15), 길의 개수 r (1 ≤ r ≤ 100)이 주어진다.

둘째 줄에는 n개의 숫자가 차례대로  각 구역에 있는 아이템의 수 t (1 ≤ t ≤ 30)를 알려준다.

세 번째 줄부터 r+2번째 줄 까지 길 양 끝에 존재하는 지역의 번호 a, b, 그리고 길의 길이 l (1 ≤ l ≤ 15)가 주어진다.

출력:

예은이가 얻을 수 있는 최대 아이템 개수를 출력한다.

풀이방법:

플로이드-와샬 알고리즘을 적용해서 이 문제를 풀 수 있다. 플로이드-와샬 알고리즘은 주어진 그래프의 경로로 가중치를 초기화한 후 i에서 j로 가는 경로에 k가 추가 되었을 때, 이전의 경로의 가중치보다 작아지는지 확인하면 된다. 

플로이드-와샬로 초기화를 완료한 뒤에, 지역의 개수 n을 반복문으로 순회한다. 순회하면서 임계점에 해당하는 값인 m보다 작은 값들을 모두 더해주고, 마지막에 현재 시작한 지역의 값을 더해주도록 한다. 이 중 가장 큰 값을 출력하도록 한다.

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
import sys
 
n,m,r = map(int,input().split())
items = list(map(int,input().split()))
MAX = float('inf')
floyd = [[MAX for _ in range(n)] for _ in range(n)]
 
for _ in range(r):
    a, b, l = map(int,input().split())
    floyd[a-1][b-1= l
    floyd[b-1][a-1= l
 
for k in range(n):
    for i in range(n):
        for j in range(n):
            floyd[i][j] = min(floyd[i][j],floyd[i][k]+floyd[k][j])
            
answer = 0
for i in range(n):
    temp = 0
    for j,v in enumerate(floyd[i]):
        if i==j:
            continue
        if v != MAX and v<=m:
            temp+=items[j]
    temp+=items[i]
    if temp >  answer:
        answer = temp
        
print(answer)
cs

문제링크:

www.acmicpc.net/problem/14938

 

14938번: 서강그라운드

예은이는 요즘 가장 인기가 있는 게임 서강그라운드를 즐기고 있다. 서강그라운드는 여러 지역중 하나의 지역에 낙하산을 타고 낙하하여, 그 지역에 떨어져 있는 아이템들을 이용해 서바이벌을

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2661. 좋은 수열  (0) 2021.01.14
[BOJ]15711. 환상의 짝꿍  (0) 2021.01.12
[BOJ]1922. 네트워크 연결  (0) 2021.01.05
[BOJ]1613. 역사  (0) 2020.12.31
[BOJ]13908. 비밀번호  (0) 2020.12.29

문제:

역사, 그 중에서도 한국사에 해박한 세준이는 많은 역사적 사건들의 전후 관계를 잘 알고 있다. 즉, 임진왜란이 병자호란보다 먼저 일어났으며, 무오사화가 기묘사화보다 먼저 일어났다는 등의 지식을 알고 있는 것이다.

세준이가 알고 있는 일부 사건들의 전후 관계들이 주어질 때, 주어진 사건들의 전후 관계도 알 수 있을까? 이를 해결하는 프로그램을 작성해 보도록 하자.

입력:

첫째 줄에 첫 줄에 사건의 개수 n(400 이하의 자연수)과 알고 있는 사건의 전후 관계의 개수 k(50,000 이하의 자연수)가 주어진다. 다음 k줄에는 전후 관계를 알고 있는 두 사건의 번호가 주어진다. 이는 앞에 있는 번호의 사건이 뒤에 있는 번호의 사건보다 먼저 일어났음을 의미한다. 물론 사건의 전후 관계가 모순인 경우는 없다. 다음에는 사건의 전후 관계를 알고 싶은 사건 쌍의 수 s(50,000 이하의 자연수)이 주어진다. 다음 s줄에는 각각 서로 다른 두 사건의 번호가 주어진다. 사건의 번호는 1보다 크거나 같고, N보다 작거나 같은 자연수이다.

출력:

s줄에 걸쳐 물음에 답한다. 각 줄에 만일 앞에 있는 번호의 사건이 먼저 일어났으면 -1, 뒤에 있는 번호의 사건이 먼저 일어났으면 1, 어떤지 모르면(유추할 수 없으면) 0을 출력한다.

풀이방법:

**python3이 아닌 pypy3으로 통과한 문제입니다.**

플로이드-와샬 알고리즘을 적용하면 쉽게 풀 수 있는 문제다. 플로이드-와샬 알고리즘은 주어진 그래프의 경로로 가중치를 초기화한 후 i에서 j로 가는 경로에 k가 추가 되었을 때, 이전의 경로의 가중치보다 작아지는지 확인하면 된다. 

이 과정을 마친 후에 a to b가 inf가 아니면 -1을, b to a가 inf가 아니면 1을 inf면 0을 출력하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import sys
 
n,m = map(int,sys.stdin.readline().split())
MAX = float('inf')
floyd = [[MAX for _ in range(n)]for _ in range(n)]
 
for _ in range(m):
    start,end = map(int,sys.stdin.readline().split())
    floyd[start-1][end-1= 1
    
for k in range(n):
    for i in range(n):
        for j in range(n):
            floyd[i][j] = min(floyd[i][j],floyd[i][k]+floyd[k][j])
 
for i in range(int(input())):
    a,b = map(int,sys.stdin.readline().split())
    if floyd[a-1][b-1!= MAX:
        print(-1)
    elif floyd[b-1][a-1!= MAX:
        print(1)
    else:
        print(0)
cs

문제링크:

www.acmicpc.net/problem/1613

 

1613번: 역사

첫째 줄에 첫 줄에 사건의 개수 n(400 이하의 자연수)과 알고 있는 사건의 전후 관계의 개수 k(50,000 이하의 자연수)가 주어진다. 다음 k줄에는 전후 관계를 알고 있는 두 사건의 번호가 주어진다.

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]14938. 서강그라운드  (0) 2021.01.07
[BOJ]1922. 네트워크 연결  (0) 2021.01.05
[BOJ]13908. 비밀번호  (0) 2020.12.29
[BOJ]11723. 집합  (0) 2020.12.24
[BOJ]1527. 금민수의 개수  (0) 2020.12.22

+ Recent posts