import sys
sys.setrecursionlimit(3000)
def input():
    return sys.stdin.readline().rstrip()

def get_diameter():
    result = 0
    visited = [0 for _ in range(N)]
    def dfs(node,tag):
        nonlocal visited
        stack = [(node,0)]
        visited[node] += 1
        max_node = -1
        max_dis = 0
        while stack:
            node,dis = stack.pop()
            if dis>max_dis:
                max_dis = dis
                max_node = node
            for next_node in graph[node]:
                if visited[next_node] == tag:
                    visited[next_node] += 1
                    stack.append((next_node,dis + graph[node][next_node]))
        return [max_node,max_dis]
    for idx in range(N):
        if visited[idx] == 0:
            far_node,_ = dfs(idx,0)
            _,dis = dfs(far_node,1)
            result += dis

    return result
N = int(input())

graph = [{} for _ in range(N)]
origin_path = []
for _ in range(N-1):
    x,y,pay = map(int,input().split())
    if x>y:
        x,y = y,x
    graph[x][y] = pay
    graph[y][x] = pay
    origin_path.append((x,y,pay))

result = get_diameter()
cnt = 0
for x,y,pay in origin_path:
    del graph[x][y]
    del graph[y][x]

    result = max(result,get_diameter()+pay)
    graph[x][y] = pay
    graph[y][x] = pay
print(result)

이 문제를 푼 사람도 적어서 안 알려진 문제이지만, 좋은 문제라 생각되어 다른 것보다 우선순위를 두어 복기를 했다.

 

이 문제의 조건을 읽어보면 하나의 트리가 주어지고, 이 트리의 간선 중 하나를 제거 한뒤,

 

이 간선을 트리의 구조를 지키면서, 간선을 추가해야하는 문제이다.

 

처음에 생각한 방법은, 트리의 간선을 제거하고, 임의의 두 노드를 뽑아서, 연결이 되어있지않다면 연결을 해주고,

 

cycle이나, 모든 노드를 통과하지 못하는 경우를 체크해주고, 트리의 지름을 구하는 식으로 생각을 했다.

 

하지만 이 방법은 2000C2 * 1999 * 트리의 지름을 구하는 복잡도가 되어 시간 초과가 날거라 생각을 했다.

 

이 문제를 푼 아이디어는 다음과 같다.

 

우리는 처음에 하나의 트리가 주어진다.

 

이 트리의 간선을 하나를 제거한다는 것은

 

2개의 트리가 된다는 것이다.

 

이 와 같은 트리가 주어진다고 하면, 

 

 

하나의 간선을 없앤다는 것은 두개의 트리로 나뉘어진다는 것으로 볼수 있다.

 

우리는 이렇게 2개로 나뉘어진 트리를 이어주고, 트리의 지름을 최대로 구할려고 하는 것이다.

 

즉, 어느 노드 끼리 이어지는 것은 중요하지 않고, 2개의 트리를 연결했을때, 트리의 지름이 최대가 될려고 하는 것이다.

 

그러면 우리가 구하는 방법은 명확해진다 우리는 잘랐던 간선의 가중치를 그대로 연결한다.

 

그렇다하면, 2개의 트리의 어느 부분을 이었을때 가장 큰 트리의 지름이 될것인지 생각해보면,

 

명확하다. 2개의 트리에서 각각 지름을 구성하는 노드들의 끝점들을 이어주면 지름의 최대값이 될것이다.

 

즉 우리는 간선을 삭제하고, 나온 트리의 지름들을 각각 구한뒤, 자른 간선의 가중치를 더해주면

 

해당 간선을 삭제하고 연결했을때의 최대 트리의 지름을 구할 수 있게 된다.

 

 

그러면 이 방식은 간선의 개수 만큼 4번의 dfs를 하면 정답을 구할수 있게 된다.

 

여기서 나는, 2개로 나뉜 트리를 구분하기 위해, visited의 방문 회수를 기점으로, 언제 방문했는지를 구분해주었다.

 

 

이 문제는 처음에 푼 사람의 수가 워낙적고, 골1이라고 책정된 난이도 때문에 풀기 어려워보였지만,

 

문제에서 계속 강조하는 트리의 지름과 트리라는 구조라는 점에 착안해서 풀수 있었던 좋은 문제였다.

 

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ/백준] 16890 창업  (0) 2022.05.11
[BOJ/백준] 19566 수열의 구간 평균  (0) 2022.01.15
[BOJ/백준] 2240 자두나무  (0) 2021.12.04
[BOJ/백준] 23291 어항정리  (0) 2021.11.07
[BOJ/백준] 23288 주사위 굴리기 2  (0) 2021.10.27

07. Component Side Effect

useEffect를 통해서 변수의 상태를 변경 시킴으로 일어나는 사이드 이펙트를 관리하는 방법을 배웠다.

  • side-effect는 부정적인 의미로만 쓰이는 것이 아닌, 한 변수의 변화로 인해 함수 외부의 값이 변화하거나 일어나는 현상을 side-effect라고 한다.

  • useState의 초기값의 lazy한 inital을 필요로 할때에는 useState(()=>window.localStorage.getItem('initial')) 를 통해 가져올 수 있다.

  • React.useEffect(() => { window.localStorage.setItem("initial",initial)},[initial])

  • useEffect라는 Hook은 update가 되었을 때, 특정작업을 하며, 컴포넌트가 mounted 됬을때와, unmount 되었을때 특정 작업을 처리할 수 있는 Hook이다.

  • 실례로, 뒤의 배열인 initial을 제거 하고, useEffect를 쓰면 최초 렌더링 시, 실행되는 것을 확인할 수 있다.

  • 용어를 정리하면, 뒤의 의존값에 들어가는 것을 deps, 그리고 return 되는 함수가 clenup

  • deps내의 의존성이 있을때에는 해당 의존성이 값이 변화할때 effect 내의 cleanup 후 useEffect내의 함수가 실행된다. (최초 렌더시에 useEffect가 실행된다.)

  • 만약 deps의 의존성이 빈배열일 때에는, 렌더시에만 실행이 된다.

  • 그리고 deps가 없을때에는 mounted 될때 useEffect가 실행이 되고, unmounted가 될때 cleanup이 실행이 된다.

  • 좀 더 자세한 설명은 밑의 링크를 보면 되고, 화면이 렌더링 되는 시점과 연관되어서는 더 공부를 해야겠다.

자세한 설명 : https://rinae.dev/posts/a-complete-guide-to-useeffect-ko

'기술공부 > React' 카테고리의 다른 글

[React] 09. Hook Flow  (0) 2021.12.23
[React] 08. Custom Hook  (0) 2021.12.23
[React] 06. Component State Handle  (0) 2021.12.16
[React] 05. event handler  (0) 2021.12.15
[React] 04. rerendring  (0) 2021.12.14

06. Component State Handle

함수형 컴포넌트에서는 컴포넌트 내부의 데이터를 사용하고, handle하기 위해서 useState라는 Hook을 사용한다.

  • useState를 사용하면, 현재의 원소상태와, 이 원소를 수정할 수 있는 setter가 주어진다.

    const [keyword, setKeyword] = React.useState("");
  • useState 안에 들어가 있는 값은 해당 value의 초기값에 해당된다.

  • 우리가 정한 setter를 통해 value를 수정할 수 있다.

  • setter를 사용하는 방법은 두 종류로, 새로운 value를 그대로 넣어주는 방법과, 함수를 넣어주는 방법이 있다.

  • 자세한 설명은 공식문서인 https://ko.reactjs.org/docs/faq-state.html 여기에 잘 설명되어 있다.

  • 새로운 value를 넣어주는 방식은 setState의 특성상 연속되는 state의 값 변경을 즉각적으로, 사용하지 못한다는 단점이 있다.

  • 왜냐하면 위의 공식설명서에서도 나와있듯이, state의 값은 즉각적으로 변화하는 것이 아니기 때문에, 이전 상태값을 가져오지 못하는 경우가 발생한다.

  • 그렇기 때문에, 과거의 값을 활용하여, 새로운 작업을 할때에는, 새로운 값을 바로 넣어주는 것보다, 함수를 통해 값을 변화시켜주는 것이 더 좋다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Static Template</title>
  </head>
  <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <body>
    <div id="root"></div>
  </body>
  <script type="text/babel">
    const rootElement = document.querySelector("#root");
    const App = () => {
      const [count, setCount] = React.useState(0);
      function handleIncrease() {
        setCount((count) => count + 1);
      }

      function handleDecrease() {
        setCount(count - 1);
      }

      function handleDoubleIncrease() {
        handleIncrease();
        handleIncrease();
      }

      function handleDoubleDecrease() {
        handleDecrease();
        handleDecrease();
      }
      return (
        <div>
          <h1>{count}</h1>
          <button onClick={handleIncrease}>+</button>
          <button onClick={handleDoubleIncrease}>2+</button>
          <button onClick={handleDecrease}>-</button>
          <button onClick={handleDoubleDecrease}>2-</button>
        </div>
      );
    };
    ReactDOM.render(<App />, rootElement);
  </script>
</html> 
  • 위 코드를 실행해보면 알지만, 2번 연속으로 더해주는 것은 정상작동하는 것에 반해, 2번연속 값을 내리는 것은 작동안하는 것을 알 수 있다.

'기술공부 > React' 카테고리의 다른 글

[React] 08. Custom Hook  (0) 2021.12.23
[React] 07. Component Side Effect  (0) 2021.12.22
[React] 05. event handler  (0) 2021.12.15
[React] 04. rerendring  (0) 2021.12.14
[React] 03.JSX  (0) 2021.12.10

05. Event Handler

리액트에서는 이벤트를 처리하는 방식은 DOM Elements에서 처리하는 방식과 유사하다.

React에서는 소문자 대신 캐멀 케이스를 사용을 하며, jsx를 사용하여, 문자열이 아닌 함수로 이벤트 핸들러를 전달하면 된다.

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 콜백에서 `this`가 작동하려면 아래와 같이 바인딩 해주어야 합니다.
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

위와 같이 jsx에서 () 를 사용하지 않고 할시에는 해당 메소드를 this에 바인딩을 하거나,

화살표 함수로 선언을 하거나 콜백에 화살표 함수를 사용하는 방법도 있다.

기본적으로 React에서는 DOM element와 동일하게 event 객체를 전달해주는데, 추가적으로 파라미터를 받고 싶으면

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

위와 같이 하면된다.

화살표함수를 통해, 전달해줄 id와 events를 명시적으로 나타내거나, bind를 통해 추가적인 인자를 추가하는 방법도 있다.

아직 컴포넌트를 통해 event를 전달하는 방식은 공부하지 않았지만, 이에 대해 공부하게 되면 추가적으로 작성하겟다.

React에서 지원하는 이벤트와 events 객체 안에 있는 값들이 궁금하면.

https://ko.reactjs.org/docs/events.html

위 링크를 통해 자세하게 읽으면 된다.

코드 출처: https://ko.reactjs.org/docs/handling-events.html

'기술공부 > React' 카테고리의 다른 글

[React] 07. Component Side Effect  (0) 2021.12.22
[React] 06. Component State Handle  (0) 2021.12.16
[React] 04. rerendring  (0) 2021.12.14
[React] 03.JSX  (0) 2021.12.10
[React] 02. Multi Element  (0) 2021.12.09

04 Reredering

react에서는 값이 변경이 되는 부분만 rerendering이 된다.

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  // highlight-next-line
  ReactDOM.render(element, document.getElementById('root'));
}

setInterval(tick, 1000);

위와 같이 매 초마다 h2의 text 값이 변경되지만, 전체를 rerender 하는 것이 아닌 실제 값이 변경된 부분에만 변경이 일어난다.

diff 알고리즘에 대해서는

https://ko.reactjs.org/docs/reconciliation.html

에 자세하게 설명이 되어있다.

memo, useMemo, useCallback으로 React 성능 최적화하기 :: Code Playground

위의 글처럼 react의 성능향상을 위해선 Hook에 대해서 더 공부해야할 것 같다.

'기술공부 > React' 카테고리의 다른 글

[React] 06. Component State Handle  (0) 2021.12.16
[React] 05. event handler  (0) 2021.12.15
[React] 03.JSX  (0) 2021.12.10
[React] 02. Multi Element  (0) 2021.12.09
[React] 01. React.CreateElement  (0) 2021.12.08

03. JSX

  • jsx는 슈가 문법으로 javascript를 확장한 문법이다.

  • React에서 javascript로 마크업을 만들고, 시각적으로 좀 더 수월하게 표현하게 해주는 방법이다.

  • JSX는 필수는 아니지만, UI 관련 작업을 할 때 도움이 된다.

  • JSX는 HTML 태그를 넣을수 있을 뿐만 아니라,

그렇기 때문에, jsx 내부에 jsx를 사용해서 만들 수 있다.

단 jsx를 활용한 태그는 파스칼케이스로 만들것을 권장한다.

그 이유는 첫글자가 대문자가 아니라면, 기존의 HTML 태그로 인식할 수 도 있기 때문이다.

const Paint = ({title, description, children}) => {
    return (
    <>
        <h1>{title}</h1>
        <h3>{children}</h3>
           {children}
    </>
)
}


const element = (
    <>
        <Paint title ="Good" description = "good">
            {Paint({title : "Bad" , description="bad" children="hi"} )}
        </Paint>
    </>
)

이렇듯 jsx 내부에 jsx를 쓸수도 있으며, 더 나아가, javascript 문법을 활용해서 return 된 jsx를 활용해서 만들수 도 있다.

'기술공부 > React' 카테고리의 다른 글

[React] 06. Component State Handle  (0) 2021.12.16
[React] 05. event handler  (0) 2021.12.15
[React] 04. rerendring  (0) 2021.12.14
[React] 02. Multi Element  (0) 2021.12.09
[React] 01. React.CreateElement  (0) 2021.12.08

02. Multi Element

React.createElement('div',{
    children : [
    React.createElement("h1",null,'first'),
    React.createElement("h3",null,'second'),
    React.createElement("h5",null,'third')
]
})


///

React.createElement(
      "div",
      null,
      React.createElement("h1", null, "first"),
      React.createElement("h3", null, "second"),
      React.createElement("h5", null, "third")
    );

///

jsx 처럼
<div> 
  <h1>first </h1>
  <h3>second</h3>
  <h5>third</h5>
</div>

위와 같은 방식으로 하나의 요소 안에 여러개의 children 을 만들 수 있다.

하지만 위와 같은 방법의 문제점은 쓸데 없는 div를 감싼다는 문제가 있다.

그렇기 때문에 React에서는 Fragment라는 tag를 지원한다.

React.createElement(React.Fragment,{
    children : [
    React.createElement("h1",null,'first'),
    React.createElement("h3",null,'second'),
    React.createElement("h5",null,'third')
]
})


///

React.createElement(
      React.Fragment,
      null,
      React.createElement("h1", null, "first"),
      React.createElement("h3", null, "second"),
      React.createElement("h5", null, "third")
    );

///

jsx
<Fragment> 
  <h1>first </h1>
  <h3>second</h3>
  <h5>third</h5>
</Fragment>

Fragment를 사용하면, 쓸데없는 div 없이 자식들을 렌더링 할 수 있다.

jsx와 React.createElement를 통해, 하나의 컴포넌트 안에 다수의 자식을 만드는 법을 배웠다.

그리고, 그 자식들이 div로 감싸지는 것이 싫으면 React에서 제공해주는 Fragment 태그를 사용해서 감싸주면 된다.

'기술공부 > React' 카테고리의 다른 글

[React] 06. Component State Handle  (0) 2021.12.16
[React] 05. event handler  (0) 2021.12.15
[React] 04. rerendring  (0) 2021.12.14
[React] 03.JSX  (0) 2021.12.10
[React] 01. React.CreateElement  (0) 2021.12.08

React

  • 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리

React.createElement()

  • jsx는 사실상 react.createElement()를 호출하기 위한 슈가 문법
  • React.createElement(
      type,
      [props],
      [...children]
    )
    type의 인자로를 div와 span 같은 tag가 와도 되고, React Component, React Fragment 타입이 올수 있다.
  • props에는 보통 attribute를 넣어준다.
  • children은 자식요소를 넣어주는거로, 문자열일수도 있으며, 컴포넌트일수도 있다.
  • 그리고 children을 props의 객체로 넣어줘도 가능하다.
  • 만약 props를 통해 children Component에 data를 넘겨주고 싶으면, function으로 만들어 놓던지 아니면 class형태로 만들어서 쓰면 된다.
  • 자세한 예제는 https://reactjs.org/docs/react-without-jsx.html
  • https://reactgo.com/react-createelement-example/ 를 쓰면 된다.

JSX 를 주로 사용하지만, JSX의 기본이 되는 React.CreateElement는 위와 같이 작용을 한다.

'기술공부 > React' 카테고리의 다른 글

[React] 06. Component State Handle  (0) 2021.12.16
[React] 05. event handler  (0) 2021.12.15
[React] 04. rerendring  (0) 2021.12.14
[React] 03.JSX  (0) 2021.12.10
[React] 02. Multi Element  (0) 2021.12.09

+ Recent posts