题目描述:给你一个n*n矩阵来表示一个图,矩阵的每个元素gij都表示i点到j点的最短路,其中对角线元素总是0。问满足这个矩阵的图的最少边数是多少,若不存在,则输出impossible。
显然,边数最多的情况是每两点之间都有最短的直边相连,边数最多为n2-n,在每两点都有最短直边相连情况下,我们以一一删去多余的边,最后就是最终结果。 考虑:若gij = gik + gkj ,i 与 j的这条边可以删去,因为i到j的最短路gij可以由gik+gkj转移来;若gij > gik + gkj ,则说明矩阵的gij并不是最短路,存在矛盾,此时则不存在这样的图,输出impossible。
还有,需要注意的是,每条边最多被删去一次,所以当一条边被删去时,需要标记,防止多次被删。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
const int LEN=105;
int path[LEN][LEN], vis[LEN][LEN], dis[LEN], n;
int floyd()
{
int ans=0;
memset(vis, 0, sizeof(vis));
for (int k=0; k<n; k++)
{
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
if ( i!=j && j!=k && i!=k )
{
if ( path[i][j]==path[i][k]+path[k][j] && !vis[i][j])
{
vis[i][j]=1;
ans++;
//break;
}
if ( path[i][j]>path[i][k]+path[k][j] )
return -1;
}
}
}
}
return ans;
}
int main()
{
int T, k;
scanf("%d", &T);
for (k=1; k<=T; k++)
{
scanf("%d", &n);
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
scanf("%d", &path[i][j]);
}
}
int ans=floyd();
printf("Case %d: ", k);
if ( ans==-1 )
{
printf("impossible\n");
}
else
{
printf("%d\n", n*(n-1)-ans);
}
}
//system("pause");
return 0;
}