zoukankan      html  css  js  c++  java
  • hdu 4034 【floyed变形】

    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
    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
     
    Sample Output
    Case 1: 6 Case 2: 4 Case 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 110
    int 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
    ",sum-ans);//总边数减去可以取消的边数就是原图最小的边数 
            else
                printf("impossible
    ");
        }
        return 0;
    }

     

  • 相关阅读:
    正则表达式30分钟入门教程
    oracle常用的字符和字符串处理类函数
    [转载]C#实现软件自动更新思路
    ORACLE函数介绍
    xml 文件操作类
    oracle 主键生成策略
    wmsys.wm_concat、sys_connect_by_path、自定义函数实现行列转换
    NSIS开始...
    Oracle分析函数详述
    常用正则表达式收集
  • 原文地址:https://www.cnblogs.com/hellocheng/p/7510804.html
Copyright © 2011-2022 走看看