世界末日燃料挑战正常线性代数失败不使用马尔可夫链中的矩阵分叉 6/10 测试用例仅通过

问题描述

编辑 - 我自己解决了。最终解决方

问题说明 Lambda 指挥官要求您通过预测给定矿石样本的最终状态来帮助科学家提高燃料生产效率。您已经仔细研究了矿石可以采用的不同结构以及它经历的转变。看起来,虽然随机,但每个结构变换的概率是固定的。也就是说,每次矿石处于 1 个状态时,它进入下一个状态(可能是相同的状态)的概率相同。您已经在矩阵中记录了观察到的转变。实验室中的其他人已经假设矿石可以变成更奇特的形式,但你还没有看到所有这些。

编写一个函数 solution(m),它采用非负整数数组表示该状态进入下一个状态的次数,并为每个终止状态返回一个整数数组,给出每个终止状态的确切概率,表示为每个状态的分子,然后以最简单的形式表示所有状态的分母。矩阵最多为 10 x 10。可以保证无论矿石处于哪种状态,都存在从该状态到终端状态的路径。也就是说,处理总是最终以稳定状态结束。矿石从状态 0 开始。在计算过程中,分母将适合一个有符号的 32 位整数,只要有规律地简化分数即可。

For example,consider the matrix m:
[
  [0,1,1],# s0,the initial state,goes to s1 and s5 with equal probability
  [4,3,2,0],# s1 can become s0,s3,or s4,but with different probabilities
  [0,# s2 is terminal,and unreachable (never observed in practice)
  [0,# s3 is terminal
  [0,# s4 is terminal
  [0,# s5 is terminal
]
So,we can consider different paths to terminal states,such as:
s0 -> s1 -> s3
s0 -> s1 -> s0 -> s1 -> s0 -> s1 -> s4
s0 -> s1 -> s0 -> s5
Tracing the probabilities of each,we find that
s2 has probability 0
s3 has probability 3/14
s4 has probability 1/7
s5 has probability 9/14
So,putting that together,and making a common denominator,gives an answer in the form of
[s2.numerator,s3.numerator,s4.numerator,s5.numerator,denominator] which is
[0,9,14].

Languages

To provide a Java solution,edit Solution.java
To provide a Python solution,edit solution.py

Test cases

Your code should pass the following test cases.
Note that it may also be run against hidden test cases not shown here.

-- Java cases --
Input:
Solution.solution({{0,0},{0,4},0}})
Output:
    [7,6,8,21]

Input:
Solution.solution({{0,1},{4,0}})
Output:
    [0,14]

我的方法

所以我正在构建一个简单的矩阵 A,其中第 i 行代表 state[i] 由其他燃料状态形成的分数/概率。 像 {{0,0}} 我的矩阵 A 将是 -

```
    [1       -4/9    0    0     0    0]
    [-1/2      1     0    0     0    0]
    [0         0     1    0     0    0]
    [0       -3/9    0    1     0    0]
    [0       -2/9    0    0     1    0]
    [-1/2     0      0    0     0    1]



    B will be Transpose of. [s0 s1 s2 s3 s4 s5]
    C will be Transpose of [1 0 0 0 0 0 0]
    
    So A x B=C
    B=A^-1 x C

```

为了保持分数,我乘以 LCM 和行列式,这样我就不会在以后将浮点数转换为分数时失去价值。所以我确保我求逆的矩阵是整数。

我的代码如下。请告诉我为什么测试用例 1,10 通过但 4,5,7 失败

import numpy as np
import random

from fractions import Fraction
from numpy.linalg import inv

# mat= Matrix([ [Fraction(1,1),Fraction(-1,2)],[Fraction(-4,9),Fraction(1,1)] ])
# x=mat.inv()


#samples
s1=[[0,[0,4],0]]
s2=[[0,[4,0]]
s3=[[0,[2,0]]



#only to generate random test cases
def generate(n):
    a=[]
    
    for i in range(n-1):
        x=[]
        partition=random.randint(0,7)
        for j in range(n):
            if partition<2:
                x.append(0)
            else:
                
                x.append(random.randint(1,300))
        a.append(x)
    x=[]
    for j in range(1):
        x.append(0)
    a.append(x)
    return a

#Main code here
def solution(s):
    sums=[]
    for i in s:
        sums.append(sum(i))
    n=len(s)
    A=[]
    for i in range(n):
        x=[]
        for j in range(n):
            x.append(Fraction(0,1))
        A.append(x)
    
    denominators=[]
    for i in range(n):
        for j in range(n):
            if i==j:
                A[i][j]+=Fraction(1)
            if sums[j]!=0:
                #normalize to make probabilty
                A[i][j]=A[i][j]-(s[j][i]*Fraction(1,sums[j]))
                denominators.append(A[i][j].denominator)
                    
    A1=np.matrix(A,dtype='float')
    
    
    arr = np.array(denominators)    
    if(sum(arr)==0):
        LCM=1
    else:
        LCM = np.lcm.reduce(arr)
    LCM=max(1,LCM)
    #TO make sure that matrix has all integers. LCM will be adjusted later
    A1=A1*LCM
    det1=int(round(np.linalg.det(A1)))
    I1=inv(A1)
    I1=I1*det1
    denom=max(det1,1)
    
    
    
    I1=I1.tolist()
    

    target=[]
    denominators=[]
    for i in range(n):
        
        if sums[i]==0:
            target.append( Fraction(round(I1[i][0]))* Fraction(LCM,int(denom)))
            denominators.append(target[-1].denominator)

    
    arr = np.array(denominators)  
    if(sum(arr)==0):
        LCM1=1
    else:
        LCM1 = np.lcm.reduce(arr)
    LCM1 = np.lcm.reduce(arr)
    #LCM1=max(1,LCM1)
    
    #print("LCM=",LCM)
    for i in range(len(target)):
        target[i]*=Fraction(LCM1,1)
        target[i]=target[i].numerator

    target.append(LCM1)

    return target

我使用的其他一些数学如下 ```

    AxB=C
    (1/LCM)x(LCM x A)xB=C
    (LCM x A)x B=LCM x C
    THis was done so that A (Now A1) always has integers
    A1 x B=LCM x C
    B= LCM x A1^-1 x C

```

进一步的行列式乘以求逆并在分母上相加,使矩阵再次成为整数,使分数可恢复

解决方案—— 感谢所有尝试过的人。我想通了这个问题。行列式变得太大而无法逆​​正变得呈指数级小。而且,当我再次乘以行列式时,数字太大了,numpy 以幂形式表示。所以信息丢失了。后来在恢复和除法时,这个数字再也没有恢复到原来的分数格式。相反,它变成了非常大的分子和分母。 解决方案很简单。不要将矩阵乘以或除以常数,最后使用分数的 limit_denomniator() 得到结果。

PS- 这是您可以在 Internet 上的任何来源上找到的最短解决方案。喜欢就点个赞吧。

"""
Created on Thu May 27 18:24:11 2021

@author: rohitsinha
"""

import numpy as np

from fractions import Fraction
from numpy.linalg import inv


# s1=[[0,0]]
# s2=[[0,0]]
# s3=[[0,0]]
# m=[
# [0,7,17,2],# [0,29,28,16,# [48,0]
# ]              

def solution(s):
    sums=[]
    for i in s:
        sums.append(sum(i))
    n=len(s)
    A=[]
    for i in range(n):
        x=[]
        for j in range(n):
            x.append(Fraction(0,1))
        A.append(x)
    
    denominators=[]
    for i in range(n):
        for j in range(n):
            if i==j:
                A[i][j]+=Fraction(1)
            if sums[j]!=0:
                A[i][j]=A[i][j]-(s[j][i]*Fraction(1,sums[j]))
                denominators.append(A[i][j].denominator)
    

    A1=np.matrix(A,dtype='float')

    I1=inv(A1)
    I1=I1.tolist()

    target=[]
    denominators=[]
    for i in range(n):
        
        if sums[i]==0:
            target.append( Fraction(I1[i][0]).limit_denominator() )
            denominators.append(target[-1].denominator)

    
    arr = np.array(denominators)  
    if(sum(arr)==0):
        LCM1=1
    else:
        LCM1 = np.lcm.reduce(arr)
    LCM1 = np.lcm.reduce(arr)

    for i in range(len(target)):
        target[i]*=Fraction(LCM1,1)
        target[i]=target[i].numerator
    target.append(LCM1)

    return target

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)