典型90【032 – AtCoder Ekiden(★3) 】をpython解説

Python

AtCoder の問題を解くために必要な実力を付けるために作られた「典型問題」を解いていく企画として、「典型90」があります。

今回は、その内、の32問目であるAtCoder Ekiden(★3)」を解説していきたいと思います。
なにか、間違っているところなどありましたら、@EitaSugiまで、ご指導ご鞭撻の程、よろしくお願い致します!

問題名 【AtCoder Ekiden(★3)】

入力
N : 走者の人数
Aij : i番目の人の区間jでの記録
M : 噂の数
Xi Yi : 仲が悪い組み合わせ

考察

今回 Nが10以下です。そのため、N人の走順の並び替えをすべて試しても、十分に間に合います
※最大で10!(=3628800)で、10^7以下のため

そのため、ありうる走順をすべて試し、i番目に走る人とi+1番目に走る人の不仲なら、そのループをブレイク(破棄)すれば良いです

そして、N人走る切ることのできた走順の中で最小のもとを出力します。

典型解法:全探索

コード

import itertools

N = int(input())
A = []#i番目に入力された人のj区目を走るときのタイムを記憶
for i in range(N):
    a = list(map(int, input().split()))
    A.append(a)

M = int(input())
bad_friends = [[] for i in range(N)]#i番目のリストにi番目の人と不仲の人を格納
for j in range(M):
    x,y = map(int, input().split())
    x -= 1#0-indexにするため-1
    y -= 1#0-indexにするため-1

    bad_friends[x].append(y)#x番目のリストに、不仲の人yを格納
    bad_friends[y].append(x)#y番目のリストに、不仲の人xを格納

ans = 10**18#初期値
number = [i for i in range(N)]#ランナーの人数

for p in itertools.permutations(number):#走る順番の並び替えを作る
    runner_time = 0#タイムを記憶
    cnt = 0#何人走ったかをカウント
    for i in range(N-1):#たすきを渡す回数
        runner = p[i]#i区目を走る人
        nxt_runner =p[i+1]#i+1区を走る人
        runner_time += A[runner][i]#i区目を走る人のタイム
        if nxt_runner not in bad_friends[runner]:#もしi+1区目を走る人が、i区目を走る人の不仲リストに入ってなければ
            cnt += 1#たすきを繋ぐ事ができる
    if cnt == N-1:#最後の走者までたすきをつなげたら
        runner_time += A[p[N-1]][N-1]#最後の走者のタイムを足す
        ans = min(ans,runner_time)#完走したときのタイムの最小値を記憶

if ans == 10**18:
    print(-1)#初期値が変わらない=どの並び替えでも完走できなかったのなら
else:#一回でも完走できたなら
    print(ans)

まとめ

前の問題【030 – K Factors(★5)】
次の問題【033 – Not Too Bright(★2)】

コメント

タイトルとURLをコピーしました