hdu 4034 【floyed变形】

来源:互联网 发布:柬埔寨翻译中文软件 编辑:程序博客网 时间:2024/06/14 10:21

Graph

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 2485    Accepted Submission(s): 1270


Problem Description
Everyone knows how to calculate the shortest path in a directed graph. In fact, the opposite problem is also easy. Given the length of shortest path between each pair of vertexes, can you find the original graph?
 

Input
The first line is the test case number T (T ≤ 100).
First line of each case is an integer N (1 ≤ N ≤ 100), the number of vertexes.
Following N lines each contains N integers. All these integers are less than 1000000.
The jth integer of ith line is the shortest path from vertex i to j.
The ith element of ith line is always 0. Other elements are all positive.
 

Output
For each case, you should output “Case k: ” first, where k indicates the case number and counts from one. Then one integer, the minimum possible edge number in original graph. Output “impossible” if such graph doesn't exist.

 

Sample Input
330 1 11 0 11 1 030 1 3 4 0 27 3 030 1 41 0 24 2 0
 

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



题意:读入矩阵,矩阵中存储的是i到j的最短路径,问,原图中的最小路径总数为多少?不存在原图,按题目输出

思路:floyed的变形。既然矩阵中存储的已经是最短路径,那么此矩阵中每条路径都必然满足最优值,比如第三个样例,直接从1到3的最短路径是4,而通过1到2(最短路径是1)再从2到3(最短路径是2)总的最短路径是3,比直接从1到3更短,不满足题目所说的条件,输出“impossible",所以,此样例给我们提供了一种思路:比较直接到达的最短路径w[i][j]和通过一个中转点k的路径w[i][k]+w[k][j]的值的大小。如果二者相等,说明直接到达的这条边取消也不影响原图,如果前者大于后者,说明不满足条件。记得定义一个标记数组,对已经访问过的点进行标记。

#include<stdio.h>#include<string.h>#define N 110int w[N][N],vis[N][N],n,sum,flag,ans;int Count(){    int i,j,k;    for(i = 1; i <= n; i ++)        for(j = 1; j <= n; j ++)            for(k = 1; k <= n; k ++)            {                if(i!=j&&j!=k&&k!=i)//自身到自身的情况不用考虑                 {                    if(w[i][j] == w[i][k] + w[k][j]&&!vis[i][j])                    {                        vis[i][j] = 1;//如果满足最短路径的条件,标记为访问过                         ans ++;//可取消的边数增加                     }                    if(w[i][j] > w[i][k] + w[k][j])//如果不满足最短路径的条件,结束函数                         return 0;                }                }    return 1;}int main(){    int t,i,j;    scanf("%d",&t);    int t2 = 0;    while(t--)    {        scanf("%d",&n);        memset(vis,0,sizeof(vis));//标记数组         for(i = 1; i <= n; i ++)            for(j = 1; j <= n; j ++)            {                scanf("%d",&w[i][j]);                if(i == j)//自身到自身的下标标记为已经访问过                     vis[i][j] = 1;            }        sum = n*n-n;//总的边数         ans = 0;        printf("Case %d: ",++t2);        if(Count())            printf("%d\n",sum-ans);//总边数减去可以取消的边数就是原图最小的边数         else            printf("impossible\n");    }    return 0;}