atcoder ABC 320 D - Relative Positionの説明

atcoder.jp

・説明
 DFSで解ける。Aiから行けるBiをDFSしていき、原点からの距離を(distx, disty)で管理する。
 注意点として、入力で

g[b].append((a,-1*c,-1*d))  

bから見たaの座標もappendしないといけないことに注意。

import sys
sys.setrecursionlimit(10**6)  

n,m=map(int,input().split())
g=[[] for _ in range(n)]
for _ in range(m):
  a,b,c,d=map(int,input().split())
  a-=1
  b-=1
  g[a].append((b,c,d))
  g[b].append((a,-1*c,-1*d))  #bから見たaの位置
#print(g)

#原点からの距離.
distx=[0 for _ in range(n)]
disty=[0 for _ in range(n)]

seen=[0 for _ in range(n)]

def dfs(v):
    seen[v]=1
    for nv,x,y in g[v]:
        if seen[nv]:
            continue
        #vから行ける点nvの距離を更新.
        distx[nv]=distx[v]+x
        disty[nv]=disty[v]+y
        dfs(nv)
        

dfs(0)

#探索済みでないなら"undecidable"を出力。
for i in range(n):
    if seen[i]==0:
        print("undecidable")
    else:
        print(distx[i],disty[i])

atcoder ABC177 D - Friendsの説明

atcoder.jp

・説明
 答えは連結成分の中で、最大の人数になる。なぜなら最大人数を全部の別々のグループに別けなければいけないからだ。   

from atcoder import dsu

n,m=map(int,input().split())

uf=dsu.DSU(n)

for i in range(m):
    a,b=map(int,input().split())
    a-=1
    b-=1
    uf.merge(a,b)

l=[0 for _ in range(n)]  

#連結成分毎の合計人数を求める.
for i in range(n):
    l[uf.leader(i)]+=1
    
print(max(l))

atcoder ARC 106 B - Valuesの勉強

atcoder.jp

・参考
 AtCoder Regular Contest 106 B – Values を解いた記録 – Manuel1024の引きこもルーム

・説明
 Union-Findを使って実装した。操作によって連結成分毎の合計は変わらないことので、もし変わっていればNoになる。
 atcoderで新しく使えるようになったac-library-python/atcoder at master · not522/ac-library-python · GitHubを使って実装した。

from atcoder import dsu

n,m=map(int,input().split())
a=list(map(int,input().split()))
b=list(map(int,input().split()))

uf=dsu.DSU(n)

for i in range(m):
    c,d=map(int,input().split())
    c-=1
    d-=1
    uf.merge(c,d)

a_sum=[0 for _ in range(n)]  #操作前の連結成分毎の合計.
b_sum=[0 for _ in range(n)]  #操作後の連結成分毎の合計.

#連結成分毎の合計を求める.
for i in range(n):
    a_sum[uf.leader(i)]+=a[i]
    b_sum[uf.leader(i)]+=b[i]

for i in range(n):
    if a_sum[i]!=b_sum[i]:
        print("No")
        exit()
print("Yes")

atcoder ABC 319 E - Bus Stopsの勉強

atcoder.jp

・参考
ABC319をPythonで解いてみたよ。(A~E問題) - Qiita

・説明
 TLEだったので、参考記事を参考にした。プログラムの説明は下のプログラムでコメントアウトしている。

import math
n,x,y=map(int,input().split())
p=[]
t=[]
for i in range(n-1):
    pi,ti=map(int,input().split())
    p.append(pi)
    t.append(ti)
    
LCM=math.lcm(*[i for i in range(1,9)])  #1-8までの最大公倍数.840.

ans=[0 for _ in range(LCM)]

#前もって、840までの問題文の答えを用意してansに代入する.
for i in range(LCM):
    ni=i+x   #バス停1につくまで.
    #バスの乗り継ぎ時間.
    for j in range(n-1):
        if ni%p[j]==0:
            ni+=t[j]
        else:
            quo=ni//p[j]  #商.
            ni=p[j]*(quo+1)+t[j]
    #バス停から青木君の家につくまでの時間.
    ni+=y   
    ans[i]=ni
    

q=int(input())
for _ in range(q):
    qi=int(input())
    quo, MOD=divmod(qi, LCM)
    print(ans[MOD]+LCM*quo)  #例えば、qi=847だとquo=1, MOD=7より、qiが7の答えにLCM*1(LCMで区切られるので)を足す.

atcoder ABC319 C - False Hopeの勉強

atcoder.jp

・参考
ABC319をPythonで解いてみたよ。(A~E問題) - Qiita

・説明
 基本的には参考記事を参考にして、問題文の通りに実装した。
 工夫としては

f=[]
for _ in range(3):
    a,b,c=map(int,input().split())
    f.append(a)
    f.append(b)
    f.append(c)

と入力を受け取ることで、そのまま見ていく順列の位置posに対して、f[pos]で値を取ってこれるようにした。

from itertools import permutations
import math
f=[]
for _ in range(3):
    a,b,c=map(int,input().split())
    f.append(a)
    f.append(b)
    f.append(c)
    
tmp=[[0,1,2],[0,3,6],[3,4,5],[6,7,8],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]  #当てはまる縦横斜め.8こある.

P=permutations([i for i in range(9)])

cnt=0
#for perm in permutations(range(9)):  #for perm in P:と同じ。
for perm in P:
    flag=1
    for t in tmp:
        T=[]
        for pos in t:  #tは[0,1,2]とかでposは0,1,2とか.
            T.append((perm[pos], f[pos]))    #perm[pos]が何番目にpos地点を見たか表す
        T.sort()  #見た順にする.
        if T[0][1]==T[1][1] and T[1][1]!=T[2][1]:  #がっかりするとき.
            flag=0
            break
    if flag:   #がっかりしなかったときをカウントする.
        cnt+=1
print(cnt/math.factorial(9))
        
        

atcoder ABC176 D - Wizard in Mazeの勉強

atcoder.jp

・やったこと
atcoder ABC 213 E - Stronger Takahashiの勉強 - stosasa’s blogでやった問題と同じようにすれば解けるのでやってみた。0-1BFSで解ける。説明は下でコメントアウトしている。

from collections import deque
H,W=map(int,input().split())
sx,sy=map(int,input().split())
sx-=1
sy-=1
gx,gy=map(int,input().split())
gx-=1
gy-=1
field=[input() for _ in range(H)]

dx=[1,0,-1,0]
dy=[0,1,0,-1]

#魔法の回数がdist。大きい値で初期化
dist=[[10**18 for _ in range(W)] for _ in range(H)]

#スタートはdist=0、queにスタートを追加
dist[sx][sy]=0
que=deque()
que.append((sx,sy))

#0-1BFS
#queがからになるまで幅優先探索をやる
while len(que)!=0:
    x,y=que.popleft()  #queの先頭のペアを取り出す
  
  
  
    #普通の移動
    for i in range(4):
        next_x=x+dx[i]
        next_y=y+dy[i]
    
        #場外はスルー
        if next_x<0 or next_x>=H or next_y<0 or next_y>=W:
            continue
        #壁もスルー
        if field[next_x][next_y]=='#':
            continue
    
        #壁がないとき、queの前から。     
        if dist[next_x][next_y]>dist[x][y]:
            dist[next_x][next_y]=dist[x][y]
            que.appendleft((next_x,next_y))
        
        
        
    #魔法の移動
    for next_x in range(x-2,x+3):  #next_xはx-2からx+2まで動く.
        for next_y in range(y-2,y+3):
            
            if next_x<0 or next_x>=H or next_y<0 or next_y>=W:  #場外のとき
                continue
            
            if field[next_x][next_y]=='#':  #壁もスルー
                continue
            
            #前の座標のdist[x][y]+1(魔法のぶん+1する)のほうが次のよりも小さいとqueの後ろからいれる
            if dist[next_x][next_y]>dist[x][y]+1:
                dist[next_x][next_y]=dist[x][y]+1
                que.append((next_x,next_y))
      
print(dist[gx][gy] if dist[gx][gy]!=10**18 else -1)

atcoder ABC 213 E - Stronger Takahashiの勉強

atcoder.jp

・参考
AtCoder ABC 213 E - Stronger Takahashi (水色, 500 点) - けんちょんの競プロ精進記録

・やったこと
 参考記事をpythonで書いて実装した。パンチすることによって2*2のマスに移動できるのでそれをコスト1、通常の移動をコスト0として0-1BFSをして、実装する。注意点として、パンチしての移動は四隅に行くことができないことに注意。

・備考 
 提出の際はPyPyで提出してください。pythonだとTLEします。

from collections import deque
H,W=map(int,input().split())
field=[input() for _ in range(H)]

dx=[1,0,-1,0]
dy=[0,1,0,-1]

#パンチを繰り出した回数がdist。大きい値で初期化
dist=[[10**18 for _ in range(W)] for _ in range(H)]

#スタートはdist=0、queにスタートを追加
dist[0][0]=0
que=deque()
que.append((0,0))

#0-1BFS
#queがからになるまで幅優先探索をやる
while len(que)!=0:
    x,y=que.popleft()  #queの先頭のペアを取り出す
  
  
  
    #普通の移動
    for i in range(4):
        next_x=x+dx[i]
        next_y=y+dy[i]
    
        #場外はスルー
        if next_x<0 or next_x>=H or next_y<0 or next_y>=W:
            continue
        #壁もスルー
        if field[next_x][next_y]=='#':
            continue
    
        #壁がないとき、queの前から。     
        if dist[next_x][next_y]>dist[x][y]:
            dist[next_x][next_y]=dist[x][y]
            que.appendleft((next_x,next_y))
        
        
        
    #パンチしての移動
    for next_x in range(x-2,x+3):  #next_xはx-2からx+2まで動く.
        for next_y in range(y-2,y+3):
            
            if next_x<0 or next_x>=H or next_y<0 or next_y>=W:  #場外のとき
                continue
            
            if abs(next_x-x)+abs(next_y-y)==4:  #四隅はいけない
                continue
            
            #前の座標のdist[x][y]+1(パンチしたぶん+1する)のほうが次のよりも小さいとqueの後ろからいれる
            if dist[next_x][next_y]>dist[x][y]+1:
                dist[next_x][next_y]=dist[x][y]+1
                que.append((next_x,next_y))
    #print(dist)
      
print(dist[H-1][W-1])

・類題
atcoder.jp