题目
https://codeforces.com/group/NVaJtLaLjS/contest/244980
题意
给你个图
mp[ i ][ j ]表示从i点到j点的距离
有的距离知道,有的距离不知道,不知道的用-1表示。
让你判断这个图有没有毛病,没有毛病的话输出它。
没有毛病的地图具有以下几点要求:
• the distance from a point to itself is zero,
• the distance between two distinct points is non-negative,
• the distance from A to B is the same as the distance from B to A, and
• the distance from A to B (directly) is less than or equal to the distance from A to B via any third point C。 i.e : d(A, B) ≤ d(A, C) + d(C, B)
思路
第一点要求: i 到 i的距离为0,对于那些含有 i 到 i 不为0的地图,输出NO
第二点要求:两点之间的距离不为负数,所以题目给你的那些用-1表示位置的点,你得用一个足够大的数字INF代替,这个INF不能超过1e9,也不能太小,避免在flody给算进去。
第三点要求:A到B跟B到A的距离得一样,最后跑图看一下一不一样,不一样输出NO。
第四点要求:两点距离最短,借助第三点的路线不能比两点直接距离短。很明显从第四点要求就能看出,过程会用到floyd算法进行操作。
一开始,我们先把所有 -1 都设置成INF,这样就满足第二点要求了。接着看看主对角线有没有问题(非0非INF),没有的话,把主对角线上的INF改成0。有的话,与第一点要求冲突,标记一会要输出NO。
然后对于其他位置,如果有题目给出i j的距离,j i距离又是INF,那么把它值对称过去。
如果i j有距离,j i也有距离,但都不等于INF,那就大条了,跟第三点要求起冲突,标记一会输出NO。这样第三点要求就验证过了。
然后,我们再用floyd算法,修改距离,然后把原始图跟修改后的图做比较,看看有没有距离变了,变了自然与第四点要求起冲突,标记一会输出NO。
如果图没毛病,输出改好的新图,
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 1000000000;
int mp[1005][1005];
int f[1005][1005];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
memset(mp,0,sizeof(mp));
memset(f,0,sizeof(f));
int n;
scanf("%d", &n);
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
{
scanf("%d", &mp[i][j]);
if(mp[i][j] == -1)
f[i][j] = INF;
else
f[i][j] = mp[i][j];
}
int flag = 0;
for(int i = 1;i <= n;i++)
{
if(f[i][i] == INF)
f[i][i] = 0;
if(f[i][i] != 0)
flag = 1;
}
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
{
if(f[i][j] == INF && f[j][i] == INF)
continue;
else
{
if (f[i][j] == INF || f[j][i] == INF)
f[i][j] = f[j][i] = min(f[i][j], f[j][i]);
else if (f[i][j] != f[j][i])
flag = 1;
}
}
for(int k = 1;k <= n;k++)
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
if (mp[i][j] == -1 || i == j)
continue;
if (mp[i][j] != f[i][j])//如果松弛了
flag = 1;
}
if(flag){
printf("NO\n");
continue;
}
else
printf("YES\n");
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)
printf("%d ",f[i][j]);
printf("\n");
}
}
return 0;
}