데이터 만들기 3
시간 제한1초메모리 제한128 MB
최적화된 벨만-포드가 C번 이내의 반복으로 끝나지만 플로이드-워셜은 C번을 넘기는 SSSP 입력 파일을 정수 T개 이하로 만들되, 사전순으로 가장 작은 것을 출력하고 없으면 -1을 출력한다.
문제
프로그래밍 대회는 많다. 대회에 쓸 좋은 문제를 내는 일은 어렵고, 테스트 데이터를 만드는 일이 그중 가장 어렵다. 좋은 테스트 데이터는 문제의 의도에 맞게 짠 코드와 그렇지 않은 코드를 구별해야 한다. 대부분의 입력에서는 맞지만 특수한 입력에서만 틀리는 코드도 잡아야 한다.
이 문제는 최단 경로를 구하는 프로그램을 제출하는 문제가 아니다. 단일 출발 최단 경로(SSSP) 형식의 테스트 데이터 하나를 출력하는 문제이다.
상근이는 코드 A(OptimizedBellmanFord)와 코드 B(FloydWarshall)를 구별하는 데이터 를 만들어야 한다. 두 코드는 내부 반복 횟수를 counter에 담는다. counter가 를 넘으면 시간 초과이다. 힌트 소스의 리터럴 1000000은 이 문제에서 로 바꾼다.
데이터 는 다음을 모두 만족해야 한다.
- 코드 A가 를 처리할 때 시간 초과가 나면 안 된다.
- 코드 B가 를 처리할 때 시간 초과가 나야 한다.
- 를 이루는 정수는 개 이하이다.
SSSP 입력 형식은 다음과 같다.
첫째 줄에 정점 수 가 나온다. 정점 번호는 부터 까지이다. 다음 개 줄 중 번째 줄()에는 정점 에서 나가는 간선 수 가 나오고, 이어서 개의 쌍 가 나온다. 는 도착 정점이고 는 가중치이다. 그다음 줄에 쿼리 수 가 나온다. 다음 개 줄에 와 가 나온다.
데이터는 아래 조건을 모두 지켜야 한다.
- 는 이상의 정수이다
- 가중치 합이 음수인 사이클이 없다
조건을 만족하는 데이터가 여러 개이면, 정수 수열로 보았을 때 사전 순으로 가장 작은 것을 고른다. 앞에서부터 비교해 처음으로 다른 위치에서 더 작은 정수를 가진 수열이 앞선다. 한쪽이 다른 쪽의 접두사이면 짧은 쪽이 앞선다.
그런 데이터가 없으면 -1을 출력한다.
입력
첫째 줄에 정수 와 가 주어진다.
출력
조건을 만족하는 데이터가 없으면 한 줄에 -1을 출력한다.
있으면 SSSP 입력 형식 그대로 출력한다. 같은 줄의 정수는 공백 하나로 구분하고, 줄 끝에 공백을 두지 않는다.
첫째 줄에 를 출력한다.
다음 줄 가운데 번째 줄(는 부터)에는 정점 의 나가는 간선 개수 를 쓰고, 이어서 개의 쌍 를 쓴다. 나가는 간선이 없으면 0만 쓴다.
그다음 줄에 를 출력한다.
다음 줄에 각 쿼리의 와 를 공백으로 구분해 출력한다.
힌트
코드 A는 최적화 벨만-포드이고, 코드 B는 플로이드-워셜이다. 아래 소스에서 리터럴 1000000은 입력 로 바꾼다. counter가 를 넘으면 시간 초과로 종료한다.
OptimizedBellmanFord:
#define INF 1000000000
int i, j, u, vv, w_u_vv, V, n, w, Q, counter, s, t;
int dist[1000];
int AdjList[1000][1000];
int weight[1000][1000];
int sz[1000];
int change;
int main() {
scanf("%d", &V);
for (i = 0; i < V; i++) {
scanf("%d", &n);
sz[i] = 0;
while (n--) {
scanf("%d %d", &j, &w);
AdjList[i][sz[i]] = j;
weight[i][sz[i]] = w;
sz[i]++;
}
}
counter = 0;
scanf("%d", &Q);
while (Q--) {
scanf("%d %d", &s, &t);
for (i = 0; i < V; i++) dist[i] = INF;
dist[s] = 0;
for (i = 0; i < V-1; i++) {
change = 0;
for (u = 0; u < V; u++)
for (j = 0; j < sz[u]; j++) {
counter++;
if (counter > 1000000) {
printf("TLE because iteration counter > 1000000\n");
return 1;
}
vv = AdjList[u][j];
w_u_vv = weight[u][j];
if (dist[u] + w_u_vv < dist[vv]) {
dist[vv] = dist[u] + w_u_vv;
change = 1;
}
}
if (!change)
break;
}
printf("%d\n", dist[t]);
}
printf("The value of counter is: %d\n", counter);
return 0;
}
FloydWarshall:
int i, j, k, V, n, w, M[300][300], counter, Q, s, t;
int main() {
scanf("%d", &V);
for (i = 0; i < V; i++)
for (j = i+1; j < V; j++)
M[i][j] = M[j][i] = 1000000000;
for (i = 0; i < V; i++)
M[i][i] = 0;
for (i = 0; i < V; i++) {
scanf("%d", &n);
while (n--) {
scanf("%d %d", &j, &w);
if (w < M[i][j]) M[i][j] = w;
}
}
counter = 0;
for (k = 0; k < V; k++)
for (i = 0; i < V; i++)
for (j = 0; j < V; j++) {
counter++;
if (counter > 1000000) {
printf("TLE because iteration counter > 1000000\n");
return 1;
}
if (M[i][k] + M[k][j] < M[i][j]) M[i][j] = M[i][k] + M[k][j];
}
scanf("%d", &Q);
while (Q--) {
scanf("%d %d", &s, &t);
printf("%d\n", M[s][t]);
}
printf("The value of counter is: %d\n", counter);
return 0;
}
플로이드-워셜은 간선 수와 쿼리와 관계없이 번 counter를 올린다. 최적화 벨만-포드는 한 라운드에서 갱신이 없으면 그 쿼리를 일찍 끝낸다.