10987. Антифлойд
В офисе компании имеется n компьютеров,
соединенные в сеть m каналами. Каждый
кабель соединяет два компьютера. Любые два компьютера соединены не более одним
кабелем. Каждый кабель имеет латентность в микросекундах, означающий время
передачи данных по нем. Маршрутизация в сети устроена так, что передача данных
от компьютера А к компьютеру В происходит за наименьшее латентное время. Кабели
двунаправленные, их латентное время одинаково в обоих направлениях.
Вы – новичок в компании и хотите определить какие
компьютеры связаны друг с другом и с каким латентным временем. Вскоре Вы
обнаружили что это сложная работа, так как в здании много этажей, а кабели
спрятаны в стенах. Тогда Вы решили от каждого компьютера послать сообщение
каждому и измерили каждую из n * (n – 1) / 2 латентностей. По этой информации
Вам следует найти латентность каждого кабеля. При вычислениях Вы хотите получить
наименьшее возможное количество кабелей.
Вход. Первая
строка содержит количество тестов N. Каждый тест начинается строкой, содержащей
значение n (0 < n < 100). Следующие
n – 1 строка содержит результаты измерений.
i-ая строка содержит i целых чисел в промежутке [1, 10000]. j-ое целое число равно латентному
времени, за которое сообщение проходит от компьютера i + 1 к j (и назад).
Выход. Для каждого теста вывести его
номер в формате “Case #x:”. Следующая строка содержит количество кабелей m. Каждая из следующих m строк содержит три целых числа: u, v
и w, означающих тот факт что между
компьютерами u и v латентность равна w.
Выводимые строки следует отсортировать по u,
потом по v, при этом u < v. Если существует несколько решений, то подойдет любое. Если
ситуация невозможна, вывести “Need better measurements.”. После каждого теста следует
выводить пустую строку.
2
3
100
200 100
3
100
300 100
Пример выхода
Case #1:
2
1 2 100
2 3 100
Case #2:
Need better measurements.
Флойд - Уоршел
Занесем результат измерений в
массив с, помня что c[i][j] = c[j][i]. Если существуют
такие индексы i, j, k, что c[i][k]
+ c[k][j] < c[i][j], то измерения не корректны и следует
вывести “Need better measurements.”. Если c[i][k] + c[k][j] = c[i][j],
то канал между i и j лишний, и его можно удалить. Для
проверки этих двух условий запускаем обычный алгоритм Флойда-Уоршела с тройным
вложенным циклом.
Результирующее количество кабелей
равно количеству ненулевых элементов среди c[i][j], где например i < j. Далее выводим эти значения согласно требуемого формата.
scanf("%d",&tests);
for(cs = 1; cs <= tests; cs++)
{
Читаем входные данные для каждого теста.
scanf("%d",&n);
memset(c,0,sizeof(c));
for(i = 2; i <= n; i++)
for(j = 1; j
< i; j++)
scanf("%d",&c[i][j]),
c[j][i] = c[i][j];
Запускаем тройной цикл Флойда – Уоршела, в теле которого
проверяем два выше описанных условия. Устанавливаем flag = 1 в случае неверных измерений.
flag = 0;
for(k = 1; k
<= n; k++) if (!flag)
for(i = 1; i
<= n; i++) if (!flag)
for(j = 1; j
<= n; j++) if (!flag)
{
if ((i ==
k) || (j == k) || (i == j)) continue;
if
(!c[i][k] || !c[k][j] || !c[i][j]) continue;
if (c[i][k]
+ c[k][j] < c[i][j]) flag = 1;
if (c[i][k]
+ c[k][j] == c[i][j]) c[i][j] = c[j][i] = 0;
}
printf("Case
#%d:\n",cs);
if (flag)
printf("Need better measurements.\n");
else
{
Вычисляем количество кабелей cables.
cables = 0;
for(i = 2;
i <= n; i++)
for(j = 1;
j < i; j++)
cables += (c[i][j] > 0);
printf("%d\n",cables);
Выводим данные о соединениях.
for(i = 1;
i <= n; i++)
for(j = i +
1; j <= n; j++)
if
(c[i][j]) printf("%d %d %d\n",i,j,c[i][j]);
}
printf("\n");
}