파이썬 알고리즘-83 (DP) 회장 뽑기

jiffydev·2020년 10월 19일
0

Algorithm

목록 보기
90/134
post-thumbnail

83.회장뽑기(플로이드-워샬 응용)
월드컵축구의 응원을 위한 모임에서 회장을 선출하려고 한다. 이모임은 만들어진지 얼마 되지 않았기 때문에 회원사이에 서로 모르는 사람도 있지만, 몇 사람을 통하면 서로 모두 알 수 있다. 각 회원은 다른 회원들과 가까운 정도에 따라 점수를 받게 된다. 예를 들어 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점이다. 어느 회원의 점수가 2점이면, 다른 모든 회원이 친구이거나, 친구의 친구임을 말한다. 또한, 어느 회원의 점수가 3점이면, 다른 모든 회원이 친구이거나, 친구의 친구이거나, 친국의 친구의 친구임을 말한다.4점, 5점등은 같은 방법으로 정해진다. 각 회원의 점수를 정할 때 주의할 점은 어떤 두 회원이 친구 사이이면서 동시에 친구의 친구 사이이면, 이 두 사람은 친구사이라고 본다. 회장은 회원들 중에서 점수가 가장 작은 사람이 된다. 회장의 점수와 회장이 될 수 있는 모든 사람을 찾는 프로그램을 작성하시오.

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

▣ 출력설명
첫째 줄은 회장 후보의 점수와 회장후보 수를 출력하고 두 번째 줄은 회장 후보를 모두 출력한다.

▣ 입력예제 1
5
1 2
2 3
3 4
4 5
2 4
5 3
-1 -1

▣ 출력예제 1
2 3
2 3 4

내 코드

n=int(input())
dy=[[0]*n for _ in range(n)]
a=b=1
# dy테이블 초기화
while a>0 and b>0:
    a,b=map(int,input().split()) 
    # break 조건을 걸지 않아 부득이하게 아래 조건을 추가했다
    if a>0 and b>0:
        # 한 쪽이 친구이면 다른 한 쪽도 친구이므로 양방향을 1로 초기화 해야 한다
        dy[a-1][b-1]=1
        dy[b-1][a-1]=1

# 플로이드 와샬 알고리즘
for k in range(n):
    for i in range(n):
        for j in range(n):
            # 자기자신일 때는 0
            if i==j:
                dy[i][j]=0
            # 관계가 없다가 새로 생겼을 때
            elif dy[i][k]>0 and dy[k][j]>0 and dy[i][j]==0:
                dy[i][j]=dy[i][k]+dy[k][j]
            # 기존의 관계보다 새로 다른 사람을 경유한 쪽이 거리가 가까울 때
            elif dy[i][k]>0 and dy[k][j]>0 and dy[i][j]>dy[i][k]+dy[k][j]:
                dy[i][j]=dy[i][k]+dy[k][j]

res=[]
for i in dy:
    # dy의 행인 i가 한 사람의 다른 사람과의 친구관계를 나타내므로 그 중 가장 큰 값을 append
    res.append(max(i))
# res의 값 중 가장 작은 값이 회장이 될 수 있는 값이고
# 그 값을 가진 사람들을 count
print(min(res), res.count(min(res)))
for j in range(len(res)):
    # 회장이 될 수 있는 값을 가진 사람들을 출력하는데
    # 지금까지 인덱스로 구한 것이므로 +1을 해준다
    if res[j]==min(res):
        print(j+1, end=' ')

풀이

if __name__=="__main__":
    n=int(input())
    dis=[[100]*(n+1) for _ in range(n+1)]
    for i in range(1, n+1):
        dis[i][i]=0
    while True:
        a, b=map(int, input().split())
        if a==-1 and b==-1:
            break
        dis[a][b]=1
        dis[b][a]=1

    for k in range(1, n+1):
        for i in range(1, n+1):
            for j in range(1, n+1):
                dis[i][j]=min(dis[i][j], dis[i][k]+dis[k][j])

    res=[0]*(n+1)
    score=100
    for i in range(1, n+1):
        for j in range(1, n+1):
            res[i]=max(res[i], dis[i][j])
        score=min(score, res[i])
    out=[]
    for i in range(1, n+1):
        if res[i]==score:
            out.append(i)
    print("%d %d" %(score, len(out)))
    for x in out:
        print(x, end=' ')

반성점

배운 것

  • 그래프에는 방향 그래프와 무방향 그래프가 있는데, 문제에서 이를 명시해주지 않는 경우도 있다. 문맥을 잘 살펴서 확인한 후 문제를 풀어야 한다.
profile
잘 & 열심히 살고싶은 개발자

0개의 댓글