본문 바로가기

백준/플로이드 워셜

[USACO] 백준 6156 - Cow Contest

728x90
728x90

https://www.acmicpc.net/problem/6156

 

힌트

더보기

어떤 소의 순서를 정확히 알기 위해선 자기보다 낮은 스킬의 소와 높은 스킬의 소의 합이 n - 1마리가 되어야 한다.

 

각 소들의 sparse 한 스킬 관계를 그래프 형태로 정리하는 방법을 생각해본다.


풀이

더보기

소의 순서를 확정하기 위해선 자기보다 높은 스킬의 소가 몇 마리인지, 자기보다 낮은 스킬의 소가 몇 마리인지 알아야 한다.

 

하지만 입력은 서로 두 소의 상하 관계만이 주어졌을 뿐이다.

 

파편화된 관계를 가지고 전체 순위를 알 수 있는 방법이 있을까?

 

사실 순위가 몇위인지 아는 건 딱히 중요하지 않고 순위가 있다는 것을 알아내기만 하면 된다.

 

각 관계를 높은 스킬의 소가 낮은 스킬의 소로 향하는 단방향 간선을 가진 그래프로 생각해보자.

 

그러면 각 소의 유불리 관계를 서로 이을 수 있고 모두 이었을 때 자신을 거치게 되는 소의 수와 다른 소로 향하는 수의 합이 n - 1개면 그 소의 순위는 결정될 수 있다.

 

관계를 잇는 것은 플로이드 워셜로 $O(N^{3})$의 시간 복잡도로 계산할 수 있으며 플로이드 워셜로 전체적인 소들의 관계를 계산한 후 각 소의 번호마다 루프를 돌면서 다른 소와 관계가 성립하는 경우를(그 소를 거쳐갈 수 있거나 자신을 거쳐오는 경우)를 더해 그 숫자가 n - 1이 되는 소를 카운팅 하여 출력하면 된다.

 

전체 코드

#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>

using namespace std;

int n, m;
int floyd[101][101];
int res;

int main()
{
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cin >> n >> m;
  fill(&floyd[0][0], &floyd[0][0] + 101 * 101, 1e9);
  for (int i = 0; i < 101; ++i)
    floyd[i][i] = 0;
  
  for (int i = 0; i < m; ++i)
  {
    int go, to;
    cin >> go >> to;
    floyd[go][to] = 0;
  }

  for (int c = 1; c <= 100; ++c)
    for (int i = 1; i <= 100; ++i)
      for(int j = 1; j <= 100; ++j)
        floyd[i][j] = min(floyd[i][j], floyd[i][c] + floyd[c][j]);
  
  for (int i = 1; i <= 100; ++i)
  {
    int cnt = 0;
    for (int j = 1; j <= 100; ++j)
    {
      if (i == j) continue;
      if (!floyd[i][j] || !floyd[j][i])
        ++cnt;
    }

    if (cnt == n - 1)
      ++res;
  }

  cout << res;
}

제출 기록

728x90
728x90

'백준 > 플로이드 워셜' 카테고리의 다른 글

백준 14588 - Line Friends (Small)  (0) 2020.05.31
백준 1043 - 거짓말  (0) 2020.05.14