Google Foobar 世界末日燃料挑战指数错误

Posted

技术标签:

【中文标题】Google Foobar 世界末日燃料挑战指数错误【英文标题】:Google Foobar Doomsday Fuel Challenge IndexError 【发布时间】:2017-08-05 01:38:41 【问题描述】:

我正在处理一个小的 python 挑战,代码在我的笔记本电脑上运行良好,但在在线控制台的第 18 行显示索引错误。 问题是

Doomsday Fuel
=============

Making fuel for the LAMBCHOP's reactor core is a tricky process because of the exotic matter involved. It starts as raw ore, then during processing, begins randomly changing between forms, eventually reaching a stable form. There may be multiple stable forms that a sample could ultimately reach, not all of which are useful as fuel. 

Commander Lambda has tasked you to help the scientists increase fuel creation efficiency by predicting the end state of a given ore sample. You have carefully studied the different structures that the ore can take and which transitions it undergoes. It appears that, while random, the probability of each structure transforming is fixed. That is, each time the ore is in 1 state, it has the same probabilities of entering the next state (which might be the same state).  You have recorded the observed transitions in a matrix. The others in the lab have hypothesized more exotic forms that the ore can become, but you haven't seen all of them.

Write a function answer(m) that takes an array of array of nonnegative ints representing how many times that state has gone to the next state and return an array of ints for each terminal state giving the exact probabilities of each terminal state, represented as the numerator for each state, then the denominator for all of them at the end and in simplest form. The matrix is at most 10 by 10. It is guaranteed that no matter which state the ore is in, there is a path from that state to a terminal state. That is, the processing will always eventually end in a stable state. The ore starts in state 0. The denominator will fit within a signed 32-bit integer during the calculation, as long as the fraction is simplified regularly. 

For example, consider the matrix m:
[
  [0,1,0,0,0,1],  # s0, the initial state, goes to s1 and s5 with equal probability
  [4,0,0,3,2,0],  # s1 can become s0, s3, or s4, but with different probabilities
  [0,0,0,0,0,0],  # s2 is terminal, and unreachable (never observed in practice)
  [0,0,0,0,0,0],  # s3 is terminal
  [0,0,0,0,0,0],  # s4 is terminal
  [0,0,0,0,0,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, 3, 2, 9, 14].

Languages
=========

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

Test cases
==========

Inputs:
    (int) m = [[0, 2, 1, 0, 0], [0, 0, 0, 3, 4], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
Output:
    (int list) [7, 6, 8, 21]

Inputs:
    (int) m = [[0, 1, 0, 0, 0, 1], [4, 0, 0, 3, 2, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
Output:
    (int list) [0, 3, 2, 9, 14]

代码是

from itertools import product 
from fractions import Fraction
from functools import reduce
#this is for matrix inversion
def invert(matrix):
    n = len(matrix)
    inverse = [[Fraction(0) for col in range(n)] for row in range(n)]
    for i in range(n):
        inverse[i][i] = Fraction(1)
    for i in range(n):
        for j in range(n):
            if i != j:
                if matrix[i][i] == 0:
                    return False
                ratio = matrix[j][i] / matrix[i][i]
                for k in range(n):
                    inverse[j][k] = inverse[j][k] - ratio * inverse[i][k]
                    matrix[j][k] = matrix[j][k] - ratio * matrix[i][k]
    for i in range(n):
        a = matrix[i][i]
        if a == 0:
            return False
        for j in range(n):
            inverse[i][j] = inverse[i][j] / a
    return inverse
#finding sum of a row in matrix
def sumRow(m, r):
    return sum(m[r])
#subtracting two matrices
def substract(matr_a, matr_b):
    output = []
    for i in range(len(matr_a)):
        tmp = []
        for valA, valB in zip(matr_a[i], matr_b[i]):
            tmp.append(valA - valB)
        output.append(tmp[:])
    return output[:]
#matrix multiplication
def matrixmult(matr_a, matr_b):
    #cols = len(matr_b[0])
    rows = len(matr_b)
    if rows is not 0:
        cols = len(matr_b[0])
    else:
        cols = 0
    resRows = range(len(matr_a))
    rMatrix = [[0] * cols for _ in resRows]
    for idx in resRows:
        for j, k in product(range(cols), range(rows)):
            rMatrix[idx][j] += matr_a[idx][k] * matr_b[k][j]
    if cols is not 0:
        return rMatrix
    else:
        return 0
    # return rMatrix
#gcd to find lcm
def gcd(a, b):
    while b:      
        a, b = b, a % b
    return a
#lcm to find last value of the output
def lcm(a,n):
    ans = a[0]
    for i in range(1,n):
        ans = (a[i]*ans)//gcd(a[i],ans)
    return ans
#main function
def answer(m):
    num = len(m)
    f=[]
    #finding zero rows
    for i in range(0,num):
        j=[]
        j.append(sumRow(m,i))
        j.append(i)
        f.append(j)
    k=0;
    #Fraction Conversion
    for i in range(0,num):
        for j in range(0,num):
            if f[i][0]!=0:
                m[i][j]=Fraction(m[i][j],f[i][0])
    j=[]
    for i in range(0,len(f)):
        if f[i][0].numerator==0:
            j.append(i)
            del m[f[i][1]-k]
            k=k+1
    q=m
    k=[]
    t=0
    e=m
   # print(m)
    q=[]
    for i in range(0,len(m)):
        row=[]
        for r in range(0,len(m[0])):
            for t in range(0,len(j)):
                if j[t] is r:
                    row.append(m[i][r])
        q.append(row)
   # print(q)
    t=0;
    w=0;
    e=[]
    for i in range(0,len(m)):
        row=[]
        flag=1
        for r in range(0,len(m[0])):
            for t in range(0,len(j)):
                if j[t] is r:
                    flag=0
                    break
            if flag is 1:
                row.append(m[i][r])
        e.append(row)
    #print(e)
    l=[]
    for i in range(0,len(e)):
        k=[]
        for b in range(0,len(e)):
            if i==b:
                k.append(1)
            else:
                k.append(0)
        l.append(k)
    #print(l)
    #print(e)
    l=substract(l,e)
    #print(l)
    l=invert(l)
    r = matrixmult(l,q)
    #print(r)
    if r == 0:
        return 0
    else:
        m =r[0]
    e=[]
    for i in range(0,len(m)):
        e.append(m[i].denominator)
    k=lcm(e,len(e))
    e=[]
    for i in range(0,len(m)):
        e.append((m[i].numerator*k)//m[i].denominator)
    e.append(k)
    #print(e)
    return e
#answer (m = [[0, 2, 1, 0, 0], [0, 0, 0, 3, 4], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]])
#answer (m = [[0, 1, 0, 0, 0, 1], [4, 0, 0, 3, 2, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]])

剩下的时间大约是 19 小时,请告诉我我在哪里做错了我对 python 完全陌生,昨天刚开始在 python 中编码,因为与 java 相比,这里处理分数很容易。

注意:在线控制台不接受 numpy 库,因此我们必须对矩阵求逆之类的东西进行硬编码

在测试各种案例后发现这个错误

Traceback (most recent call last):
  File "C:\Users\python.py", line 148, in <module>
    answer (m = [[0, 2, 1, 0, 0], [0, 0, 0, 3, 4], [0, 0, 0, 0, 0], [0, 4, 0, 0, 0], [0, 0, 0, 0, 0]])
  File "C:\Users\python.py", line 131, in answer
    l=invert(l)
  File "C:\Users\python.py", line 18, in invert
    matrix[j][k] = matrix[j][k] - ratio * matrix[i][k]
IndexError: list index out of range

【问题讨论】:

能否请您发布出现错误时的完整回溯? 编译器不会给出完整的回溯,但在第 18 行给出的错误只是编辑了问题,谢谢 :) 我想不出您所看到的可能是什么原因,但您确实在 invert 函数中有错字。你有两行return false,应该是return False 谢谢!更改了代码,但错误仍然保持不变:/ @FamousJameous 对描述进行了小修改,请立即查看 【参考方案1】:

当您为行 matrix[j][k] = matrix[j][k] - ratio * matrix[i][k] 引用的列表索引不在列表中时,会生成该错误。我不太确定为什么会在我测试你的 def inverse(matrix) 代码并且它通过了我所有的测试用例时生成它。你搞清楚了吗?

【讨论】:

是的!逆(矩阵)函数没有错误,它做得很好。但是错误出现在 answer(matrix) 函数中,以某种方式正在生成一个非方阵并传递给该 inverse() 函数,因此它正在生成错误。我通过检查矩阵的行和列的长度并仅在它是方阵时才通过来解决它

以上是关于Google Foobar 世界末日燃料挑战指数错误的主要内容,如果未能解决你的问题,请参考以下文章

python 在Google的Foobar挑战中尝试练习级别3.1“查找访问代码”失败。

python 在Google的Foobar挑战中尝试练习级别3.1“查找访问代码”失败。

Google Foobar Challenge,一个测试用例失败

Google Foobar 测试用例失败

Google X——这可能是世界上最奇葩的科技圣地

世界核燃料循环大会由Tecnatom赞助举行