행렬을 입력 받았을 때 그에 해당하는 역행렬을 출력하는 코드를 작성해보세요. 추가로 행렬식이 0인경우는 따로 역행렬이 존재하지 않음을 표현해 주세요.
예시
입력
[1, 1, 1, 1]
[1, 2, 3, 4]
[2, 1, 3, 1]
[1, 0, 3, 4]
출력
[1.8, -0.8, -0.2, 0.4]
[0. 0.5, 0, -0.5]
[-1.4, 0.4, 0.6, -0.2]
[0.6, -0.1, -0.4, 0.3]
입력
[1, 1, 1]
[2, 4, 2]
[3, 3, 5]
출력
[3.5, -0.5, -0.5]
[-1, 0.5, 0]
[-1.5, 0, 0.5]
8개의 풀이가 있습니다.
Javascipt(ES6)...
`가우스-요르단 소거법으로 역행렬을 구함. (https://terms.naver.com/entry.nhn?docId=3338111&ref=y&cid=47324&categoryId=47324) 에서 가우스-요르단 소거법 문항 참고함.
역행렬을 구할 수 없는 경우에는 각 요소가 Infinity 혹은 NaN 으로 출력됨`;
class Matrix {
constructor(m) {
this.matrix = m;
this.size = m.length;
}
// 역행렬 계산하여, 새로운 인스턴스 생성
inverse_matrix() {
// 단위행렬 identity 생성
let identity = [];
for(let r = 0; r < this.size; r++) {
identity[r] = [];
for(let c = 0; c < this.size; c++) {
identity[r][c] = (r == c) ? 1 : 0;
}
}
// 첨가행렬 augmented 생성
let augmented = [];
for(let r = 0; r < this.size; r++) {
augmented[r] = [...this.matrix[r], ...identity[r]];
}
// 가우스-요르단 소거법으로 역행렬 계산
for(let c = 0; c < this.size; c++) {
for(let r = 0; r < this.size; r++) {
if(r == c || augmented[r][c] == 0) { continue; }
let m = augmented[c][c] / augmented[r][c];
augmented[r] = augmented[r].map((v, i) => v * m - augmented[c][i]);
}
}
for(let r = 0; r < this.size; r++) {
let m = augmented[r][r];
augmented[r] = augmented[r].map(v => v / m);
}
// augmented 에서 역행렬 inverse 에 해당하는 부분만 발췌
let inverse = [];
for(let r = 0; r < this.size; r++) {
inverse[r] = augmented[r].slice(this.size);
}
return new Matrix(inverse);
}
// 행렬 출력, 소수점 4자리까지만 출력
print_matrix() {
let output = '';
for(let r = 0; r < this.size; r++) {
output += '[ ';
for(let c = 0; c < this.size ; c++) {
output += this.matrix[r][c].toFixed(4).replace(/\.?0*$/,'') + ((c == this.size - 1) ? ' ' : ', ');
}
output += ']\n';
}
console.log(output);
}
}
let m_1 = [
[1, 1, 1, 1],
[1, 2, 3, 4],
[2, 1, 3, 1],
[1, 0, 3, 4],
];
new Matrix(m_1).inverse_matrix().print_matrix();
let m_2 = [
[1, 1, 1],
[2, 4, 2],
[3, 3, 5],
];
new Matrix(m_2).inverse_matrix().print_matrix();
n=int(input("행렬의 크기를 입력하세요:"))
q=[] #이중리스트를 위한 도구
m=[]
for x in range(n):
for y in range(n):
q.append(int(input("{}행{}열 원소를 입력하세요".format(x+1,y+1))))
m.append(q)
q=[]
for x in range(n):
print(m[x])
inv=[]
for x in range(n):
for y in range(n):
q.append(0)
inv.append(q)
q=[]
for x in range(n):
inv[x][x]=1
print(inv) #여기까지 inv는 역행렬로변환될 항등행렬, m은 정해짐
aug=[] #m,i의 첨가행렬
for x in range(n):
aug.append(q)
for x in range(n):
aug[x]=m[x]+inv[x]
print(aug)
k=1
a=[]
b=[] #임시저장소
'''
while aug[0][0]==0 and k != n:
a=aug[0]
b=aug[k]
aug[0]=b
aug[k]=a #aug를 새로 정의하는거라 =으로 정의하는건안전함
k+=1
k=1
if aug[0][0]==0:
print("역행렬이 존재하지 않습니다.")
else:
for x in range(1,n):
for y in range(0,2*n):
aug[x][y]-= (aug[x][0]/aug[0][0])*aug[0][y]
print(aug)
''' # 첫번재 열에대한 연산... 이걸 모든행에 적용시켜야함
k=1
for t in range(n-1):
while aug[t][t]==0 and k != n:
a=aug[t]
b=aug[k]
aug[t]=b
aug[k]=a #aug를 새로 정의하는거라 =으로 정의하는건안전함
k+=1
k=t+2
if aug[t][t]==0:
print("역행렬이 존재하지 않습니다.")
else:
for x in range(t+1,n):
c=(aug[x][t]/aug[t][t])
for y in range(0,2*n):
aug[x][y]-=c*aug[t][y]
#왜 첫열만빼는거지? 첫번재항을 수행하고나면, 첫번째 값이 바뀜. 즉 기준이 바뀌어버려서 연산결과가 달라지네... 기준을 또사용하는건 주의가필요함...
for x in range(n):
if aug[x][x]==0:
print("역행렬이 존재하지 않습니다.")
break
for x in range(n):
print(aug[x])
#이렇게하면 역삼각행렬이 나온다 여기까지만해도 역행렬의 존재여부를 파악 가능하다.
for t in range(1,n):
for x in range(0,t):
c=(aug[x][t]/aug[t][t])
for y in range(0,2*n):
aug[x][y]-=c*aug[t][y] #대각행렬 완성
for x in range(n):
print(aug[x])
for x in range(n):
c=aug[x][x]
for y in range(2*n):
aug[x][y]/=c
for x in range(n):
print(aug[x][n:2*n])
m=[]; p=[]; inv=[]; q=[]
a=0; det=1; k=0
size = int(input("행렬의 크기:"))
for x in range(size):
for y in range(size):
p.append(int(input("%s행%s열 원소: " % (x+1, y+1))))
m.append(p)
p=[]
for x in range(size):
for y in range(size):
if x==y:
q.append(1)
else:
q.append(0)
inv.append(q)
q=[]
while k<len(m):
if m[k][k]==0:
m = m[k+1:len(m)]+m[k:k+1]
inv = inv[k+1:len(inv)]+inv[k:k+1]
continue
else:
if m[k][k]==1:
for i in range(k+1, len(m)):
a = -m[i][k]
for j in range(len(m)):
if a == 0:
break
m[i][j] = a*m[k][j]+m[i][j]
inv[i][j] = a*inv[k][j]+inv[i][j]
else:
a=1/m[k][k]
for i in range(len(m)):
m[k][i]=m[k][i]*a
inv[k][i]=inv[k][i]*a
for i in range(k+1, len(m)):
a = -m[i][k]
for j in range(len(m)):
if a == 0:
break
m[i][j] = a*m[k][j]+m[i][j]
inv[i][j] = a*inv[k][j]+inv[i][j]
k=k+1
for i in range(len(m)):
det *= m[i][i]
if det == 0:
print('역행렬이 존재하지지 않습니다.')
else:
for k in range(len(m)-1, -1, -1):
for i in range(k-1, -1, -1):
a = -m[i][k]
for j in range(len(m)-1, -1, -1):
if a == 0:
break
m[i][j]=a*m[k][j]+m[i][j]
inv[i][j]=a*inv[k][j]+inv[i][j]
for i in range(len(m)):
for j in range(len(m)):
inv[i][j] = '%.1f' % inv[i][j]
for row in inv:
print(row)
import numpy as np
import numpy.linalg as li
data=[1,1,1,1,1,2,3,4,2,1,3,1,1,0,3,4]
ary=np.array(data).reshape(4,4)
try:
print(li.inv(ary))
except:
print("역행렬 존재 X")
from copy import deepcopy
from fractions import Fraction
def bk(mat__, c, d, e) : # 기본 행변형 : d행에서 c행의 e배를 뺍니다
for re in range(0, len(mat__)) :
mat__[d][re] -= mat__[c][re]*e
return deepcopy(mat__)
def ik(mat_, a, b) : # 기본 행변형 : a행과 b행을 바꿉니다
tem = []
tem = mat_[b]
mat_[b] = mat_[a]
mat_[a] = tem
return deepcopy(mat_)
def printOut(r) : # 결과 출력
rr = []
for i in r :
rr.append(deepcopy(list(map(float, i))))
return rr
def one(mat) :
try :
## 결과를 단위행렬로서 초기화
result = deepcopy([list(map(int, " ".join(bin(2**(len(mat)-1-i))[2:].zfill(len(mat)).split()))) for i in range(0, len(mat))])
#계단화 할 수 있도록 행 배열 변형
for c in range(0, len(mat)) :
for cc in range(c, len(mat)) :
if mat[cc][c] != 0 :
mat = ik(mat, c, cc)
result = ik(result, c, cc)
break
for ch in range(0, len(mat)) :
if mat[ch][ch] == 0 :
for tr in range(0, len(mat)) :
if mat[tr][ch] != 0 and mat[ch][tr] != 0:
mat = ik(mat, tr, ch)
result = ik(result, tr, ch)
break
for ne in range(0, len(mat)) : # 행렬 대각성분을 그 크기로 나눠 1로 만듭니다
if mat[ne][ne] != 1 :
alt_var = deepcopy(mat[ne][ne])
for di in range(0, len(mat)) :
mat[ne][di] = Fraction(mat[ne][di], alt_var)
result[ne][di] = Fraction(result[ne][di], alt_var)
for ne_ in range(0, len(mat)) : # 행변형(bk)로 각 대각성분을 제외한 자신의 열 성분이 모두 0이 되도록 합니다
if mat[ne_][ne] != 0 and ne != ne_ :
alt_var_2 = deepcopy(mat[ne_][ne])
mat = bk(mat, ne, ne_, alt_var_2)
result = bk(result, ne, ne_, alt_var_2)
return printOut(result)
except :
return "역행렬이 존재하지 않습니다."
if __name__ == "__main__" :
print(one([[1, 1, 1, 1],[1, 2, 3, 4],[2, 1, 3, 1],[1, 0, 3, 4]]))
print(one([[1, 1, 1, 1],[2, 1, 3, 1],[2, 1, 3, 1],[1, 0, 3, 4]]))
print(one([[1, 1, 1], [2, 4, 2], [3, 3, 5]]))
print(one([[3, 2], [3, 2]]))
결과
[[1.8, -0.8, -0.2, 0.4], [0.0, 0.5, 0.0, -0.5], [-1.4, 0.4, 0.6, -0.2], [0.6, -0.1, -0.4, 0.3]]
역행렬이 존재하지 않습니다.
[[3.5, -0.5, -0.5], [-1.0, 0.5, 0.0], [-1.5, 0.0, 0.5]]
역행렬이 존재하지 않습니다.
파이썬으로 코드 짜는게 오랜만이라서 쓸데없이 길이가 긴 느낌이네요. 다음에 시간이 나면 좀더 보기 좋게 정리해보도록 하겠습니다.
import numpy as np
def makeInv(n, arr):
arr = np.linalg.inv(arr)
for r in range(n):
for c in range(n):
arr[r,c] = round(arr[r,c], 2)
return arr
#A = [[1, 1, 1, 1],[1, 2, 3, 4],[2, 1, 3, 1],[1, 0, 3, 4]]
A = [[1, 1, 1],[2, 4, 2],[3, 3, 5]]
n = len(A)
arr = np.array(A)
print(arr)
print(" ="*5, '역행렬')
print(makeInv(n, arr))
def printArr(n, arr2):
print('[', end='')
for r in range(n):
print('[', end='')
for c in range(n):
print('{0}'.format(arr2[r][c]), end=' ')
if r == n-1:
print(']]')
else:
print(']')
print(end=' ')
print()
def makeInv(n, arr):
zArr = [[0 for j in range(n)] for i in range(n)]
for i in range(n):
zArr[i][i] = 1
for s in range(n-1):
for i in range(s, n-1):
if arr[s][s] == 0:
k = s+1
while k<n-1 and arr[k][s] == 0:
k += 1
for l in range(n):
arr[s][l], arr[k][l] = arr[k][l], arr[s][l]
tmp = arr[i + 1][s] / arr[s][s]
for j in range(n):
zArr[i+1][j] -= (zArr[s][j] * tmp)
arr[i+1][j] -= (arr[s][j] * tmp)
for s in range(n-1, 0, -1):
for i in range(s, 0, -1):
tmp = arr[i - 1][s] / arr[s][s]
for j in range(n):
zArr[i-1][j] -= (zArr[s][j] * tmp)
arr[i-1][j] -= (arr[s][j] * tmp)
for i in range(n):
for j in range(n):
zArr[i][j] = round(zArr[i][j]/arr[i][i], 2)
arr[i][j] /= arr[i][i]
#printArr(n, arr)
printArr(n, zArr)
# arr = [[1, 1, 1],[2, 4, 2],[3, 3, 5]]
# makeInv(3, arr)
arr = [[1, 1, 1, 1],[1, 2, 3, 4],[2, 1, 3, 1],[1, 0, 3, 4]]
makeInv(4, arr)