已知有向图任意两点的最短距离,求最小边数

来源:互联网 发布:apache安装与配置 编辑:程序博客网 时间:2024/05/17 07:26

题目描述

相信大家都会解决有向图的最短路问题。这次我们反着来,给你一个有向图中每一对顶点之间的最短路的长度,请你计算出原图中最少可能包含多少条边。

输入格式

输入的第一行是一个整数T(T<=10),表示有T组测试数据。
每组输入的第一行是一个整数N(1<=N<=100),表示顶点个数。
接下来N行,每行输入N个整数,这些整数都小于10000。
第i行的第j个整数表示从顶点i到顶点j的最短路的长度。
第i行的第i个数字一定是0,其他的数字都大于0。

输出

对于每组输入,先输出“Case k: ”,k表示样例的序号,从1开始。然后输出一个整数,表示原图中最少可能包含多少条边。如果原图不存在,则输出“impossible”(引号不输出)。

样例输入

3
3
0 1 1
1 0 1
1 1 0
3
0 1 3 
4 0 2
7 3 0
3
0 1 4
1 0 2
4 2 0

样例输出

Case 1: 6
Case 2: 4
Case 3: impossible


先假设map[i][j]只要i!=j就存在一条边,跑一遍floyd就知道是否有解,再跑一遍floyd,如果map[i][k]+map[k][j]==map[i][j],显然map[i][j]这条边可以去掉。。

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int t,n;int map[110][110];bool vis[110][110];int dis[110][110];int main(){    int ca=1;    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        memset(vis,0,sizeof(vis));        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)                scanf("%d",&map[i][j]),dis[i][j]=map[i][j];        for(int k=0;k<n;k++)        {            for(int i=0;i<n;i++)                for(int j=0;j<n;j++)                {                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);                }        }        int tag=1;        for(int i=0;i<n&&tag;i++)            for(int j=0;j<n&&tag;j++)            {                if(map[i][j]!=dis[i][j])                {                    tag=0;break;                }            }        if(!tag)        {            printf("Case %d: impossible\n",ca++);            continue;        }        for(int k=0;k<n;k++)        {            for(int i=0;i<n;i++)                for(int j=0;j<n;j++)                {                    if(vis[i][k]==0&&vis[k][j]==0&&vis[i][j]==0)                    {                        if(i!=k&&i!=j&&j!=k&&map[i][k]+map[k][j]==map[i][j])                        {                            vis[i][j]=1;                            map[i][j]=10000000000;                        }                    }                }        }        int ans=0;        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)                if(!vis[i][j]&&i!=j) {ans++;}        printf("Case %d: %d\n",ca++,ans);    }}


原创粉丝点击