题目链接:http://codeforces.com/gym/102190/attachments
题解:先按照题目要求遍历一下数组,若存在不满足题目要求的直接输出NO,其他的:先将主对角线上的元素变为0,若存在对称方面,如果一方面可变化一方面固定,则另一方面可以随之确定,而如果两面都是可变化(-1),那么将这个点变为10000000,随之跑一波Floyd找解,(如果存在不可变化的点,也能在此过程中变化,则输出NO)看代码比较好理解~
#include<iostream>
#include<cstring>
using namespace std;
const int INF=10000000;
int n,t;
int a[505][505],vis[505][505];//vis标记该点是否可以更改(即是否是-1)
int main()
{
std::ios::sync_with_stdio(0);
cin>>t;
while(t--)
{
memset(vis,0,sizeof(vis));
cin>>n;
int flag=1;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
cin>>a[i][j];
if(a[i][j]==-1)
a[i][j]=INF;
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(i==j)
{
if(a[i][j]!=INF&&a[i][j]!=0)//自己到自己的距离不为0并且不可变动
flag=0;
else
a[i][j]=0;
}
else
{
if(a[i][j]==INF&&a[j][i]==INF)//两点都标记为可更改的点
vis[i][j]=vis[j][i]=1;
else if(a[i][j]==INF)//若只有一边可更改,则可以直接确定该点值
a[i][j]=a[j][i];
else if(a[j][i]==INF)
a[j][i]=a[i][j];
else if(a[i][j]!=a[j][i])//最后如果两点不可更改,并且值又不同,则不满足题给条件
flag=0;
}
}
}
for(int k=1; k<=n; k++)//跑一波Floyd 求条件最短路即可
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(a[i][j]>a[i][k]+a[k][j])
{
if(vis[i][j])//该点可以变动才能变动
a[i][j]=a[i][k]+a[k][j];
else //否则不能满足题给条件
flag=0;
}
}
}
}
if(flag==0)
cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(j==n)
cout<<a[i][j]<<endl;
else
cout<<a[i][j]<<" ";
}
}
}
}
return 0;
}