Matrix Exponentiation用于计算可能的路线数量

时间:2016-10-07 18:12:17

标签: c++ algorithm vector matrix-multiplication

最近我在Iarcs网站上遇到了this问题。这是问题陈述:

  

众所周知,互联网上使用的路由算法是   非常不理想。在互联网术语中," hop"是一对节点   直接连接 - 通过电缆或微波链路或   随你。数据包从一个数据包中获取的跃点数   节点到另一个节点可能远远超过最低要求。

     

但Siruseri Network公司使用的路由算法是   更差。在这里,从一个节点发送到另一个节点的数据包甚至可以去   通过相同的节点两次或甚至之前两次遍历同一跳   它最终找到了通往目的地的道路。有时一个包   甚至在它之前不止一次经过目的地   考虑"交付"。假设Siruseri的网络由   以下节点和电缆:图

     

有5个节点和8个电缆链路。注意,一对节点可以是   由多个链接连接。这些被认为是不同的   酒花。所有链接都是双向的。从节点1到节点5的数据包可以,   例如,旅行如下:1至2,2至1,1至3,3至2,2至   1,1至4,4至5,5至4,4至5.该路由长度为9(   跳数是给定路由的长度)。我们感兴趣的是   计算从给定来源到a的不同路线的数量   具有给定长度的目标。

     

例如,长度为3的1到2的路由数量为7。   它们如下(以;分隔):1比2,2比1和1比2; 1到   3,3比1和1比2; 1至4,4至1和1至2; 1至5,5至1和1   到2; 1至4,4至3(通过左侧电缆)和3至2; 1到4,4到3   (通过正确的电缆)和3到2; 1至2,2至3和3至2。

     

您将获得Siruseri网络的描述以及   一个源,一个目标和跳数,你的任务是   确定从源到目标的路由数量   有给定的跳数。答案是以模数报告   42373

正如在this线程中所讨论的,解决方案是计算给定矩阵的幂k,其中k是给定的路由数。

我在这里做了同样的事情:

#include <iostream>
#include <vector>

std::vector<std::vector<int> >MatrixMultiplication(std::vector<std::vector<int> >matrix1,std::vector<std::vector<int> >matrix2,int n){
    std::vector<std::vector<int> >retMatrix(n,std::vector<int>(n));

    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            for(int k=0;k<n;k++){
                retMatrix[i][j] = retMatrix[i][j] + matrix1[i][k] * matrix2[k][j];
            }
        }
    }

    return retMatrix;
}

std::vector<std::vector<int> >MatrixExponentiation(std::vector<std::vector<int> >matrix,int n,int power){
    if(power == 0 || power == 1){
        return matrix;
    }

    if(power%2 == 0){
        return MatrixExponentiation(MatrixMultiplication(matrix,matrix,n),n,power/2);
    }else{
        return MatrixMultiplication(matrix,MatrixExponentiation(MatrixMultiplication(matrix,matrix,n),n,(power-1)/2),n);
    }
}

int main (int argc, char const* argv[])
{
    int n;
    std::cin >> n;
    std::vector<std::vector<int> >matrix(n,std::vector<int>(n));
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            std::cin >> matrix[i][j];
        }
    }
    int i ,j ,power;
    std::cin >> i >> j >> power;
    std::vector<std::vector<int> >retMax(n,std::vector<int>(n));
    retMax = MatrixExponentiation(matrix,n,power);
    std::cout << matrix[i-1][j-1] << std::endl;
    return 0;
}

但即使对于示例案例,输出也不匹配,我在这里遗漏了什么,或者我必须尝试另一种方法解决这个问题?

编辑:正如@grigor建议我更改了power == 0的代码以返回单位矩阵,但代码仍会产生错误的输出,

if(power == 0){
        std::vector<std::vector<int> >retMatrix(n,std::vector<int>(n));
        for(int i=0;i<n;i++){
            retMatrix[i][i] = 1;
        }
        return retMatrix;
    }

注意:我还没有编写modulo的代码,你认为它会对示例测试用例有效吗?

2 个答案:

答案 0 :(得分:4)

如果power == 0你应该返回单位矩阵,而不是实际的矩阵。

答案 1 :(得分:4)

我认为你只是打印出错误的值,改变:

DECLARE @source VARCHAR(max) = 'A1,B1,C1,D1,E1,F1,G1;A2,B2,C2,D2,E2,F2,G2;A3,B3,C3,D3,E3,F3,G3;A4,B4,C4,D4,E4,F4,G4;A5,B5,C5,D5,E5,F5,G5;A6,B6,C6,D6,E6,F6,G6;A7,B7,C7,D7,E7,F7,G7;A8,B8,C8,D8,E8,F8,G8;A9,B9,C9,D9,E9,F9,G9;A10,B10,C10,D10,E10,F10,G10;A11,B11,C11,D11,E11,F11,G11;A12,B12,C12,D12,E12,F12,G12;A13,B13,C13,D13,E13,F13,G13;A14,B14,C14,D14,E14,F14,G14;A15,B15,C15,D15,E15,F15,G15;A16,B16,C16,D16,E16,F16,G16;A17,B17,C17,D17,E17,F17,G17;A18,B18,C18,D18,E18,F18,G18;A19,B19,C19,D19,E19,F19,G19;A20,B20,C20,D20,E20,F20,G20'

-- First determine the columns names. Since the string can be potential very long we don’t want to parse the entire string to determine how many columns 
-- we have, instead get sub string of main string up to first row delimiter.
DECLARE @firstRow VARCHAR(max) = LEFT(@source, CHARINDEX(';', @source) - 1);
DECLARE @columnNames NVARCHAR(MAX) = '';

-- Use string splitter function on sub string to determine column names.
SELECT @columnNames = STUFF(( 
                                SELECT ',' + QUOTENAME(CAST(ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS VARCHAR(10)))
                                FROM        [dbo].[SplitString](@firstRow, ',') Items
                                FOR XML PATH('')), 1, 1, '');

-- Next build dynamic query that will generate our matrix table.
-- CTE first split string by row delimiters then it applies the string split function again on each row.  
DECLARE @pivotQuery NVARCHAR(MAX) ='
;WITH CTE_SplitData AS
(
SELECT       R.Nr AS [Row]
            ,C.[Columns]
            ,ROW_NUMBER() OVER (PARTITION BY R.Nr ORDER BY R.Item) AS ColumnNr
FROM        [dbo].[SplitString](@source, '';'') R
OUTER APPLY (
                SELECT  Item AS [Columns]
                FROM    [dbo].[SplitString](R.Item, '','') 
            ) C
)
-- Pivoted reuslt
SELECT * FROM
(  
     SELECT * 
     FROM   CTE_SplitData
)as T
PIVOT 
(
     max(T.[Columns])
     for T.[ColumnNr] in (' +  @columnNames + ')
) as P'


EXEC sp_executesql  @pivotQuery,
          N'@source VARCHAR(MAX)',  
          @source = @source;        -- Pass the source string to be split as a parameter to the dynamic query.

std::cout << matrix[i-1][j-1] << std::endl;