core algorithm: dfs