zoukankan      html  css  js  c++  java
  • sql server: 最短路径

    ---------------------------------------------------------------------
    -- Road System  道路
    ---------------------------------------------------------------------
    
    -- Listing 9-3: DDL & Sample Data for Cities, Roads
    SET NOCOUNT ON;
    USE tempdb;
    GO
    IF OBJECT_ID('dbo.Roads') IS NOT NULL
      DROP TABLE dbo.Roads;
    GO
    IF OBJECT_ID('dbo.Cities') IS NOT NULL
      DROP TABLE dbo.Cities;
    GO
    
    CREATE TABLE dbo.Cities
    (
      cityid  CHAR(3)     NOT NULL PRIMARY KEY,
      city    VARCHAR(30) NOT NULL,
      region  VARCHAR(30) NULL,
      country VARCHAR(30) NOT NULL
    );
    
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('ATL', 'Atlanta', 'GA', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('ORD', 'Chicago', 'IL', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('DEN', 'Denver', 'CO', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('IAH', 'Houston', 'TX', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('MCI', 'Kansas City', 'KS', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('LAX', 'Los Angeles', 'CA', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('MIA', 'Miami', 'FL', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('MSP', 'Minneapolis', 'MN', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('JFK', 'New York', 'NY', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('SEA', 'Seattle', 'WA', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('SFO', 'San Francisco', 'CA', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('ANC', 'Anchorage', 'AK', 'USA');
    INSERT INTO dbo.Cities(cityid, city, region, country)
      VALUES('FAI', 'Fairbanks', 'AK', 'USA');
    
    CREATE TABLE dbo.Roads
    (
      city1       CHAR(3) NOT NULL REFERENCES dbo.Cities,
      city2       CHAR(3) NOT NULL REFERENCES dbo.Cities,
      distance INT     NOT NULL,
      PRIMARY KEY(city1, city2),
      CHECK(city1 < city2),
      CHECK(distance > 0)
    );
    
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ANC', 'FAI', 359);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'ORD', 715);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'IAH', 800);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'MCI', 805);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'MIA', 665);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'JFK', 865);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'IAH', 1120);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'MCI', 600);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'LAX', 1025);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'MSP', 915);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'SEA', 1335);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'SFO', 1270);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('IAH', 'MCI', 795);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('IAH', 'LAX', 1550);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('IAH', 'MIA', 1190);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('JFK', 'ORD', 795);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('LAX', 'SFO', 385);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('MCI', 'ORD', 525);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('MCI', 'MSP', 440);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('MSP', 'ORD', 410);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('MSP', 'SEA', 2015);
    INSERT INTO dbo.Roads(city1, city2, distance) VALUES('SEA', 'SFO', 815);
    GO
    
    
    
    SELECT * FROM dbo.Roads
    GO
    
    WITH Roads2  --每对城市生成行
    AS
    (
    	SELECT city1 AS from_city,city2 AS to_city FROM dbo.Roads
    	UNION ALL 
    	SELECT city2,city2 FROM dbo.Roads
    ),
    RoadPaths AS
    (
    --返回第一级别的所有可到达的城市对
    	SELECT from_city,to_city, 
    	CAST('.'+from_city+'.'+to_city+'.' AS VARCHAR(max)) AS path
    	FROM Roads2
    	UNION ALL
        SELECT F.from_city,T.to_city,--返回下一级别的可到达的城市对
    	CAST(F.path+T.to_city+'.' AS VARCHAR(MAX)) --路径需要验明循环
    	FROM RoadPaths AS F
    	JOIN Roads2 AS T
    	ON CASE WHEN F.path LIKE '%.'+T.to_city+'.%' --如果to_city出现在from_city的路径中,则检测到循环
    		THEN 1 ELSE 0 END =0
    	AND F.to_city =T.from_city
    )
    SELECT DISTINCT from_city,to_city FROM RoadPaths;--返回Roads 的传递包
    GO
    
    
    
    ---------------------------------------------------------------------
    -- Undirected Cyclic Graph
    ---------------------------------------------------------------------
    
    -- Listing 9-38: Transitive Closure of Roads (Undirected Cyclic Graph) 传递闭包
    WITH Roads2 -- Two rows for each pair (f-->t, t-->f)
    AS
    (
      SELECT city1 AS from_city, city2 AS to_city FROM dbo.Roads
      UNION ALL
      SELECT city2, city1 FROM dbo.Roads
    ),
    RoadPaths AS
    (
      -- Return all first-level reachability pairs
      SELECT from_city, to_city,
        -- path is needed to identify cycles
        CAST('.' + from_city + '.' + to_city + '.' AS VARCHAR(MAX)) AS path
      FROM Roads2
    
      UNION ALL
    
      -- Return next-level reachability pairs
      SELECT F.from_city, T.to_city,
        CAST(F.path + T.to_city + '.' AS VARCHAR(MAX))
      FROM RoadPaths AS F
        JOIN Roads2 AS T
          -- if to_city appears in from_city's path, cycle detected
          ON CASE WHEN F.path LIKE '%.' + T.to_city + '.%'
                  THEN 1 ELSE 0 END = 0
          AND F.to_city = T.from_city
    )
    -- Return Transitive Closure of Roads
    SELECT DISTINCT from_city, to_city
    FROM RoadPaths;
    GO
    
    -- Listing 9-39: Creation Script for the fn_RoadsTC UDF
    IF OBJECT_ID('dbo.fn_RoadsTC') IS NOT NULL
      DROP FUNCTION dbo.fn_RoadsTC;
    GO
    
    CREATE FUNCTION dbo.fn_RoadsTC() RETURNS @RoadsTC TABLE (
      from_city VARCHAR(3) NOT NULL,
      to_city   VARCHAR(3) NOT NULL,
      PRIMARY KEY (from_city, to_city)
    )
    AS
    BEGIN
      DECLARE @added as INT;
    
      INSERT INTO @RoadsTC(from_city, to_city)
        SELECT city1, city2 FROM dbo.Roads;
    
      SET @added = @@rowcount;
    
      INSERT INTO @RoadsTC
        SELECT city2, city1 FROM dbo.Roads
    
      SET @added = @added + @@rowcount;
    
      WHILE @added > 0 BEGIN
    
        INSERT INTO @RoadsTC
          SELECT DISTINCT TC.from_city, R.city2
          FROM @RoadsTC AS TC
            JOIN dbo.Roads AS R
              ON R.city1 = TC.to_city
          WHERE NOT EXISTS
            (SELECT * FROM @RoadsTC AS TC2
             WHERE TC2.from_city = TC.from_city
               AND TC2.to_city = R.city2)
            AND TC.from_city <> R.city2;
    
        SET @added = @@rowcount;
    
        INSERT INTO @RoadsTC
          SELECT DISTINCT TC.from_city, R.city1
          FROM @RoadsTC AS TC
            JOIN dbo.Roads AS R
              ON R.city2 = TC.to_city
          WHERE NOT EXISTS
            (SELECT * FROM @RoadsTC AS TC2
             WHERE TC2.from_city = TC.from_city
               AND TC2.to_city = R.city1)
            AND TC.from_city <> R.city1;
    
        SET @added = @added + @@rowcount;
      END
      RETURN;
    END
    GO
    
    -- Use the fn_RoadsTC UDF  --传递闭包函数
    SELECT * FROM dbo.fn_RoadsTC();
    GO
    
    -- Listing 9-40: All paths and distances in Roads (15262 rows)返回所有路径和距离
    WITH Roads2
    AS
    (
      SELECT city1 AS from_city, city2 AS to_city, distance FROM dbo.Roads
      UNION ALL
      SELECT city2, city1, distance FROM dbo.Roads
    ),
    RoadPaths AS
    (
      SELECT from_city, to_city, distance,
        CAST('.' + from_city + '.' + to_city + '.' AS VARCHAR(MAX)) AS path
      FROM Roads2
    
      UNION ALL
    
      SELECT F.from_city, T.to_city, F.distance + T.distance,
        CAST(F.path + T.to_city + '.' AS VARCHAR(MAX))
      FROM RoadPaths AS F
        JOIN Roads2 AS T
          ON CASE WHEN F.path LIKE '%.' + T.to_city + '.%'
                  THEN 1 ELSE 0 END = 0
          AND F.to_city = T.from_city
    )
    -- Return all paths and distances
    SELECT * FROM RoadPaths;
    GO
    
    
    -- Listing 9-41: Shortest paths in Roads 返回最短路径
    WITH Roads2
    AS
    (
      SELECT city1 AS from_city, city2 AS to_city, distance FROM dbo.Roads
      UNION ALL
      SELECT city2, city1, distance FROM dbo.Roads
    ),
    RoadPaths AS
    (
      SELECT from_city, to_city, distance,
        CAST('.' + from_city + '.' + to_city + '.' AS VARCHAR(MAX)) AS path
      FROM Roads2
    
      UNION ALL
    
      SELECT F.from_city, T.to_city, F.distance + T.distance,
        CAST(F.path + T.to_city + '.' AS VARCHAR(MAX))
      FROM RoadPaths AS F
        JOIN Roads2 AS T
          ON CASE WHEN F.path LIKE '%.' + T.to_city + '.%'
                  THEN 1 ELSE 0 END = 0
          AND F.to_city = T.from_city
    ),
    RoadsMinDist -- Min distance for each pair in TC 每对城市的最短距离
    AS
    (
      SELECT from_city, to_city, MIN(distance) AS mindist
      FROM RoadPaths
      GROUP BY from_city, to_city
    )
    -- Return shortest paths and distances 返回最短路径和距离
    SELECT RP.*
    FROM RoadsMinDist AS RMD
      JOIN RoadPaths AS RP
        ON RMD.from_city = RP.from_city
        AND RMD.to_city = RP.to_city
        AND RMD.mindist = RP.distance;
    GO
    
    
    
    -- Listing 9-42: Load Shortest Road Paths Into a Table 把最短路径保存到表
    WITH Roads2
    AS
    (
      SELECT city1 AS from_city, city2 AS to_city, distance FROM dbo.Roads
      UNION ALL
      SELECT city2, city1, distance FROM dbo.Roads
    ),
    RoadPaths AS
    (
      SELECT from_city, to_city, distance,
        CAST('.' + from_city + '.' + to_city + '.' AS VARCHAR(MAX)) AS path
      FROM Roads2
    
      UNION ALL
    
      SELECT F.from_city, T.to_city, F.distance + T.distance,
        CAST(F.path + T.to_city + '.' AS VARCHAR(MAX))
      FROM RoadPaths AS F
        JOIN Roads2 AS T
          ON CASE WHEN F.path LIKE '%.' + T.to_city + '.%'
                  THEN 1 ELSE 0 END = 0
          AND F.to_city = T.from_city
    ),
    RoadsMinDist
    AS
    (
      SELECT from_city, to_city, MIN(distance) AS mindist
      FROM RoadPaths
      GROUP BY from_city, to_city
    )
    SELECT RP.*
    INTO dbo.RoadPaths
    FROM RoadsMinDist AS RMD
      JOIN RoadPaths AS RP
        ON RMD.from_city = RP.from_city
        AND RMD.to_city = RP.to_city
        AND RMD.mindist = RP.distance;
    
    CREATE UNIQUE CLUSTERED INDEX idx_uc_from_city_to_city
      ON dbo.RoadPaths(from_city, to_city);
    GO
    
    -- Return shortest path between Los Angeles and New York 测试查询最短路径
    SELECT * FROM dbo.RoadPaths 
    WHERE from_city = 'LAX' AND to_city = 'JFK';
    GO
    
    -- Listing 9-43: Creation Script for the fn_RoadsTC UDF
    IF OBJECT_ID('dbo.fn_RoadsTC') IS NOT NULL
      DROP FUNCTION dbo.fn_RoadsTC;
    GO
    CREATE FUNCTION dbo.fn_RoadsTC() RETURNS @RoadsTC TABLE
    (
      uniquifier INT          NOT NULL IDENTITY,
      from_city  VARCHAR(3)   NOT NULL,
      to_city    VARCHAR(3)   NOT NULL,
      distance   INT          NOT NULL,
      route      VARCHAR(MAX) NOT NULL,
      PRIMARY KEY (from_city, to_city, uniquifier)
    )
    AS
    BEGIN
      DECLARE @added AS INT;
    
      INSERT INTO @RoadsTC
        SELECT city1 AS from_city, city2 AS to_city, distance,
          '.' + city1 + '.' + city2 + '.'
        FROM dbo.Roads;
    
      SET @added = @@rowcount;
    
      INSERT INTO @RoadsTC
        SELECT city2, city1, distance, '.' + city2 + '.' + city1 + '.'
        FROM dbo.Roads;
    
      SET @added = @added + @@rowcount;
    
      WHILE @added > 0 BEGIN
        INSERT INTO @RoadsTC
          SELECT DISTINCT TC.from_city, R.city2,
            TC.distance + R.distance, TC.route + city2 + '.'
          FROM @RoadsTC AS TC
            JOIN dbo.Roads AS R
              ON R.city1 = TC.to_city
          WHERE NOT EXISTS
            (SELECT * FROM @RoadsTC AS TC2
             WHERE TC2.from_city = TC.from_city
               AND TC2.to_city = R.city2
               AND TC2.distance <= TC.distance + R.distance)
            AND TC.from_city <> R.city2;
    
        SET @added = @@rowcount;
    
        INSERT INTO @RoadsTC
          SELECT DISTINCT TC.from_city, R.city1,
            TC.distance + R.distance, TC.route + city1 + '.'
          FROM @RoadsTC AS TC
            JOIN dbo.Roads AS R
              ON R.city2 = TC.to_city
          WHERE NOT EXISTS
            (SELECT * FROM @RoadsTC AS TC2
             WHERE TC2.from_city = TC.from_city
               AND TC2.to_city = R.city1
               AND TC2.distance <= TC.distance + R.distance)
            AND TC.from_city <> R.city1;
    
        SET @added = @added + @@rowcount;
      END
      RETURN;
    END
    GO
    
    -- Return shortest paths and distances
    SELECT from_city, to_city, distance, route
    FROM (SELECT from_city, to_city, distance, route,
            RANK() OVER (PARTITION BY from_city, to_city
                         ORDER BY distance) AS rk
          FROM dbo.fn_RoadsTC()) AS RTC
    WHERE rk = 1;
    GO
    
    -- Cleanup
    DROP TABLE dbo.RoadPaths;
    GO
    

      

  • 相关阅读:
    pro-engineer&UG
    鸡肋
    中国计算机软件设计师考试大纲 2008-10-12 21:51 鹤影314 | 五级
    成为JAVA软件开发工程师要学哪些东西
    爱上一匹野马,可我的家里没有草原,这让我感到绝望。
    理解MySQL——架构与概念
    理解MySQL——索引与优化
    负载均衡与高可用概念(转)
    Nginx Rewrite详解(转)
    Nginx 反向代理配置实例(转)
  • 原文地址:https://www.cnblogs.com/geovindu/p/7049074.html
Copyright © 2011-2022 走看看