만드는 중입니다

아직 만드는 중이라 바뀔 수 있습니다

다익스트라를 초과시키는 그래프

시간 제한1초메모리 제한128 MB

요약
플로이드-워셜은 시간 안에 끝나지만 우선순위 큐를 쓰는 다익스트라는 시간 초과가 나도록, 정해진 규칙대로 만든 방향 가중 그래프를 그대로 출력한다.
난이도

쉬움10점 중 3점

유형
그래프, 최단 경로, 구현
정답자
아직 제출이 없습니다

문제

프로그래밍 대회용 테스트 데이터를 만드는 일은 어렵다. 좋은 데이터는 문제의 의도에 맞게 짠 코드와 그렇지 않은 코드를 가려내야 한다. 대부분의 입력에서는 맞지만 특수한 입력에서만 틀리는 코드도 잡아야 한다.

이 문제는 최단 경로 프로그램 두 개를 구분하는 방향 가중치 그래프를 출력한다. 그래프 XX는 다음을 만족해야 한다.

  1. 코드 A(플로이드-워셜)가 XX를 처리할 때 시간 초과가 나면 안 된다.
  2. 코드 B(변형 다익스트라)가 XX를 처리할 때 시간 초과가 나야 한다.

각 코드는 연산 횟수를 세는 카운터를 둔다. 카운터 값이 10610^6을 넘으면 시간 초과이다. 데이터는 작을수록 좋으므로 출력하는 정수는 157157개 이하여야 한다.

플로이드-워셜은 정점 수 VV에 대해 카운터를 정확히 V3V^3만큼 올린다. 따라서 V≤100V \le 100이면 코드 A는 시간 초과가 아니다.

변형 다익스트라는 우선순위 큐에 같은 정점을 여러 번 넣는다. 음수 간선이 있으면 큐에서 꺼내는 횟수가 지수로 늘 수 있다. 아래 삼각형 장치를 kk개 이어 붙이면 변형 다익스트라의 카운터는 지수로 커지고, 플로이드-워셜의 카운터는 (2k+1)3(2k+1)^3에 머문다.

조건을 만족하는 그래프는 여럿일 수 있다. 채점은 아래 규칙으로 유일하게 정해진 그래프만 정답으로 본다.

V=2k+1V = 2k+1로 두고 정점 번호는 00부터 2k2k까지로 둔다. 간선은 모두 방향 간선이다.

  • 정점 00의 나가는 간선은 없다.
  • 정점 11은 정점 00으로 가중치 11인 간선 하나를 보낸다.
  • 정점 22는 정점 11로 가중치 11인 간선 하나를 보낸다.
  • 각 정수 t=1,2,…,k−1t = 1, 2, \ldots, k-1에 대해 다음을 따른다.
    • 정점 2t+12t+1은 정점 2t2t로 가중치 −2⋅2t-2 \cdot 2^{t}인 간선 하나를 보낸다.
    • 정점 2t+22t+2는 두 간선을 보낸다. 첫 간선은 정점 2t+12t+1로 가고 가중치는 2t2^{t}이다. 둘째 간선은 정점 2t2t로 가고 가중치는 00이다.

질의는 하나이다. 시작 정점은 2k2k이고 도착 정점은 00이다.

입력

첫 줄에 삼각형 장치의 개수 kk가 주어진다. (1≤k≤161 \le k \le 16)

이 kk에 대해 V=2k+1≤33V = 2k+1 \le 33이므로 플로이드-워셜 카운터는 10610^6을 넘지 않는다. 출력 정수 개수는 8k+38k+3이며 157157 이하이다. 모든 가중치 ww는 ∣w∣<106|w| < 10^6을 만족한다.

출력

위에서 정한 그래프를 다음 형식으로 출력한다.

첫 줄에 정점 수 VV를 출력한다.

다음 VV줄 가운데 ii번째 줄은 정점 ii의 나가는 간선을 적는다. ii는 00부터 시작한다. 줄의 첫 정수 nin_i는 나가는 간선의 개수이다. 그 뒤에 nin_i개의 정수 쌍 jj ww를 한 칸으로 구분해 출력한다. jj는 도착 정점이고 ww는 가중치이다. 한 정점에 간선이 여러 개이면 문제에서 적은 순서대로 출력한다.

그다음 줄에 질의 수 11을 출력한다.

마지막 줄에 2k2k와 00을 한 칸으로 구분해 출력한다.

힌트

코드 A와 코드 B의 카운터는 다음 의사 코드처럼 움직인다.

플로이드-워셜:

counter = 0
for x = 0 to V-1
    for i = 0 to V-1
        for j = 0 to V-1
            counter = counter + 1
            M[i][j] = min(M[i][j], M[i][x] + M[x][j])

변형 다익스트라 (질의마다 반복):

dist[s] = 0
pq.push((0, s))
while pq is not empty
    counter = counter + 1
    (d, u) = pq.pop()
    if d == dist[u]
        for each edge (u, v, w) from u
            if dist[u] + w < dist[v]
                dist[v] = dist[u] + w
                pq.push((dist[v], v))

우선순위 큐는 거리 값이 더 작은 쌍을 먼저 꺼낸다.

예제3

  1. 예제 1

    입력
    1
    
    예상 출력
    3
    0
    1 0 1
    1 1 1
    1
    2 0
    
  2. 예제 2

    입력
    2
    
    예상 출력
    5
    0
    1 0 1
    1 1 1
    1 2 -4
    2 3 2 2 0
    1
    4 0
    
  3. 예제 3

    입력
    3
    
    예상 출력
    7
    0
    1 0 1
    1 1 1
    1 2 -4
    2 3 2 2 0
    1 4 -8
    2 5 4 4 0
    1
    6 0