안녕횽아들 난 1년동안 프갤 눈팅만 한 고딩이야요.
장마가 내리는 여름날 대회준비하다가 필요해서 미지수가 16개인 연립방정식을 풀게됬어요.
좌표평면 위에 점 16개를 지나는 x,y에 대한 3차함수 f(x,y) = ∑∑aij*x^i*y^j 를 구하게된거야요.
사람이 할짓이 아니라서 스마트하게 행렬방정식으로 바꿔서 풀라고 했음요
16x16 역행렬 구하는 프로그램 찾아서
( http://blog.naver.com/PostView.nhn?blogId=dltjdgns8888&logNo=130108226392 )
위에 주소에 있는인간이 미련하게 C코드로 어설픈 동적할당으로 메모리 누수 일으키고 앉아있길래
C++로 바꾼다음에 메모리문제 해결하고, 다시 한번 해봤는데 1시간을 돌려도 안되네요?
참고로 내 노트북 씨퓨 i7 요
동적할당 안쓰려고 일부러 메타프로그래밍까지 했는데 컴퓨터가 왜이렇게 수줍어하는지
결과가 쳐느리게 나옴요
아래는 코드요
----------------------------
#include <stdio.h>
// 행렬의 크기는 그대로 사용하되, 행과 열은 실제보다 1 작은 값을 사용한다.
template <size_t _Size>
struct Matrix {
double _Data[_Size*_Size];
inline double& operator[](size_t _Size) { return _Data[_Size]; }
inline double operator[](size_t _Size) const { return _Data[_Size]; }
inline double& operator()(size_t _X, size_t _Y) { return _Data[_X+_Y*_Size]; }
inline double operator()(size_t _X, size_t _Y) const { return _Data[_X+_Y*_Size]; }
void PrintMatrix() const {
for(size_t i=0;i<_Size*_Size;i++)
{
printf(\"%+.8lf \", _Data[i]);
if(i % _Size == _Size - 1) putchar(\'\\n\');
}
}
};
// i행 j열에 대한 소행렬
template<size_t _Size>
Matrix<_Size-1> MinorMat(Matrix<_Size> mat, size_t row, size_t col) {
size_t i,j,k=0; // i:행카운트, j:열카운트, k:소행렬 원소 카운트
Matrix<_Size-1> minorMat;
// 기존행렬보다 한사이즈 작은 소행렬 동적생성.
for(i=0;i<_Size;i++) if(i!=row) for(j=0;j<_Size;j++) if(j!=col) minorMat[k++]=mat[i*_Size+j];
// 기존행렬의 i행원소,j열원소를 제외한 원소를 소행렬에 채운다.
return minorMat; // 소행렬 반환
}
//행렬식 = 1행j열 원소 x 1행j열 여인수 총합.
//여기서, 1행j열 여인수 = (-1)^(1+j) x 소행렬식의 행렬식이다.
template<size_t _Size>
double Determinant(const Matrix<_Size>& mat) {
double det=0; // 행렬식 저장
for(size_t j=0;j<_Size;j++) det+=mat[j]*(j%2 ? -1 : 1)*(Determinant(MinorMat(mat,0,j)));
return det; // 구한 행렬식 반환
}
template<>
inline double Determinant(const Matrix<3U>& a) {
return
a(0,0)*(a(1,1)*a(2,2)-a(1,2)*a(2,1)) -
a(0,1)*(a(1,0)*a(2,2)-a(1,2)*a(2,0)) +
a(0,2)*(a(1,0)*a(2,1)-a(1,1)*a(2,0)); }
template<>
inline double Determinant(const Matrix<2U>& a) {
return a[0]*a[3]-a[1]*a[2]; }
template<>
inline double Determinant(const Matrix<1U>& a) {
return a[0]; }
void main(void) {
const size_t Size = 8U;
Matrix<Size> myMat, cfMat, transMat, invMat;
// 행렬입력
printf(\"> %u x %u 행렬을 입력합니다.\\n\",Size,Size);
printf(\" (%d개의 값을 빈칸(또는 엔터)으로 구분하여 입력하세요.)\\n\",Size*Size);
for(size_t i=0;i<Size*Size;i++) scanf_s(\"%lf\", &myMat[i]);
putchar(\'\\n\');
myMat.PrintMatrix(); // 입력한 행렬 출력
putchar(\'\\n\');
// 행렬식
double det=Determinant(myMat);
printf(\"> det(myMat) is %5.2lf\", det);
// 여인수 행렬 구하기
for(size_t i=0;i<Size;i++) for(size_t j=0;j<Size;j++)
cfMat(j,i)=((i+j)%2 ? -1 : 1)*(Determinant(MinorMat(myMat,i,j)));
//i행j열 여인수 = (-1)^(i+j) x 소행렬식의 행렬식.
// 수반 행렬
// 전치행렬 구하기
for(size_t i=0;i<Size;i++) for(size_t j=0;j<Size;j++) transMat(i,j)=cfMat(j,i);
// 행과 열을 바꾼후 전치행렬에 저장.
printf(\"\\n\\n> 전치행렬...\\n\");
transMat.PrintMatrix();
// 역행렬 구하기
// 인자로 받은 수반행렬의 각원소를 행렬식으로 나눈값을 역행렬에 저장.
for(size_t i=0;i<Size*Size;++i) invMat[i]=transMat[i]/det;
printf(\"\\n\\n> 역행렬...\\n\");
invMat.PrintMatrix();
// 잠시 정지..
fflush(stdin); // (스페이스바나 엔터키가 입력값으로 채워지지 않기위함)
getchar();
}
-------------------------
힘들게 코드읽어보신 형아들 미안해요 결국 재귀함수 썼다요 흑흑
남들 다 하는것처럼 멋있게 for문만 갖고 동적계획법인가 뭔가로 풀어볼려고했는데
내 머리로는 도저히 안되더라고요 ㅏ하하하하
__fastcall써보고, 64빗으로 컴파일하고, 컴파일러 옵션 무조건 빠르게만 해놓고
더이상 할 발악이 없어서 스택가지고 멀티스레딩도 해보려고 했는데,
결국 제일 근본적인 문제는 시간복잡도라는걸 난 이미 알고있지요
하루동안 여기에 매달렸는데 컴퓨터로는 도저히 못하겠어요
흑흑 난 고딩이고 프로그래밍 좋아하는데 학원다닐새가 없어서
다들 제일 기본으로 배운다는 알고리즘은 한번도 배워본적이 없음요 늅늅늅
혹시 프갤에서 해적왕이 되어보고 싶으신분들
불쌍한 중생구제한다고 생각하시면서 조언이라도 해줘요
그동안 난 손으로 풀고있어야짘ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
장마가 내리는 여름날 대회준비하다가 필요해서 미지수가 16개인 연립방정식을 풀게됬어요.
좌표평면 위에 점 16개를 지나는 x,y에 대한 3차함수 f(x,y) = ∑∑aij*x^i*y^j 를 구하게된거야요.
사람이 할짓이 아니라서 스마트하게 행렬방정식으로 바꿔서 풀라고 했음요
16x16 역행렬 구하는 프로그램 찾아서
( http://blog.naver.com/PostView.nhn?blogId=dltjdgns8888&logNo=130108226392 )
위에 주소에 있는인간이 미련하게 C코드로 어설픈 동적할당으로 메모리 누수 일으키고 앉아있길래
C++로 바꾼다음에 메모리문제 해결하고, 다시 한번 해봤는데 1시간을 돌려도 안되네요?
참고로 내 노트북 씨퓨 i7 요
동적할당 안쓰려고 일부러 메타프로그래밍까지 했는데 컴퓨터가 왜이렇게 수줍어하는지
결과가 쳐느리게 나옴요
아래는 코드요
----------------------------
#include <stdio.h>
// 행렬의 크기는 그대로 사용하되, 행과 열은 실제보다 1 작은 값을 사용한다.
template <size_t _Size>
struct Matrix {
double _Data[_Size*_Size];
inline double& operator[](size_t _Size) { return _Data[_Size]; }
inline double operator[](size_t _Size) const { return _Data[_Size]; }
inline double& operator()(size_t _X, size_t _Y) { return _Data[_X+_Y*_Size]; }
inline double operator()(size_t _X, size_t _Y) const { return _Data[_X+_Y*_Size]; }
void PrintMatrix() const {
for(size_t i=0;i<_Size*_Size;i++)
{
printf(\"%+.8lf \", _Data[i]);
if(i % _Size == _Size - 1) putchar(\'\\n\');
}
}
};
// i행 j열에 대한 소행렬
template<size_t _Size>
Matrix<_Size-1> MinorMat(Matrix<_Size> mat, size_t row, size_t col) {
size_t i,j,k=0; // i:행카운트, j:열카운트, k:소행렬 원소 카운트
Matrix<_Size-1> minorMat;
// 기존행렬보다 한사이즈 작은 소행렬 동적생성.
for(i=0;i<_Size;i++) if(i!=row) for(j=0;j<_Size;j++) if(j!=col) minorMat[k++]=mat[i*_Size+j];
// 기존행렬의 i행원소,j열원소를 제외한 원소를 소행렬에 채운다.
return minorMat; // 소행렬 반환
}
//행렬식 = 1행j열 원소 x 1행j열 여인수 총합.
//여기서, 1행j열 여인수 = (-1)^(1+j) x 소행렬식의 행렬식이다.
template<size_t _Size>
double Determinant(const Matrix<_Size>& mat) {
double det=0; // 행렬식 저장
for(size_t j=0;j<_Size;j++) det+=mat[j]*(j%2 ? -1 : 1)*(Determinant(MinorMat(mat,0,j)));
return det; // 구한 행렬식 반환
}
template<>
inline double Determinant(const Matrix<3U>& a) {
return
a(0,0)*(a(1,1)*a(2,2)-a(1,2)*a(2,1)) -
a(0,1)*(a(1,0)*a(2,2)-a(1,2)*a(2,0)) +
a(0,2)*(a(1,0)*a(2,1)-a(1,1)*a(2,0)); }
template<>
inline double Determinant(const Matrix<2U>& a) {
return a[0]*a[3]-a[1]*a[2]; }
template<>
inline double Determinant(const Matrix<1U>& a) {
return a[0]; }
void main(void) {
const size_t Size = 8U;
Matrix<Size> myMat, cfMat, transMat, invMat;
// 행렬입력
printf(\"> %u x %u 행렬을 입력합니다.\\n\",Size,Size);
printf(\" (%d개의 값을 빈칸(또는 엔터)으로 구분하여 입력하세요.)\\n\",Size*Size);
for(size_t i=0;i<Size*Size;i++) scanf_s(\"%lf\", &myMat[i]);
putchar(\'\\n\');
myMat.PrintMatrix(); // 입력한 행렬 출력
putchar(\'\\n\');
// 행렬식
double det=Determinant(myMat);
printf(\"> det(myMat) is %5.2lf\", det);
// 여인수 행렬 구하기
for(size_t i=0;i<Size;i++) for(size_t j=0;j<Size;j++)
cfMat(j,i)=((i+j)%2 ? -1 : 1)*(Determinant(MinorMat(myMat,i,j)));
//i행j열 여인수 = (-1)^(i+j) x 소행렬식의 행렬식.
// 수반 행렬
// 전치행렬 구하기
for(size_t i=0;i<Size;i++) for(size_t j=0;j<Size;j++) transMat(i,j)=cfMat(j,i);
// 행과 열을 바꾼후 전치행렬에 저장.
printf(\"\\n\\n> 전치행렬...\\n\");
transMat.PrintMatrix();
// 역행렬 구하기
// 인자로 받은 수반행렬의 각원소를 행렬식으로 나눈값을 역행렬에 저장.
for(size_t i=0;i<Size*Size;++i) invMat[i]=transMat[i]/det;
printf(\"\\n\\n> 역행렬...\\n\");
invMat.PrintMatrix();
// 잠시 정지..
fflush(stdin); // (스페이스바나 엔터키가 입력값으로 채워지지 않기위함)
getchar();
}
-------------------------
힘들게 코드읽어보신 형아들 미안해요 결국 재귀함수 썼다요 흑흑
남들 다 하는것처럼 멋있게 for문만 갖고 동적계획법인가 뭔가로 풀어볼려고했는데
내 머리로는 도저히 안되더라고요 ㅏ하하하하
__fastcall써보고, 64빗으로 컴파일하고, 컴파일러 옵션 무조건 빠르게만 해놓고
더이상 할 발악이 없어서 스택가지고 멀티스레딩도 해보려고 했는데,
결국 제일 근본적인 문제는 시간복잡도라는걸 난 이미 알고있지요
하루동안 여기에 매달렸는데 컴퓨터로는 도저히 못하겠어요
흑흑 난 고딩이고 프로그래밍 좋아하는데 학원다닐새가 없어서
다들 제일 기본으로 배운다는 알고리즘은 한번도 배워본적이 없음요 늅늅늅
혹시 프갤에서 해적왕이 되어보고 싶으신분들
불쌍한 중생구제한다고 생각하시면서 조언이라도 해줘요
그동안 난 손으로 풀고있어야짘ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
blitz라는 cpp용 수학라이브러리가 있다. 템플릿을 극단적으로 사용중인 라이브러리인데 이 물건은 lazy evaluation, tmp를 활용해서 실행시간중 속도를 극단적으로 끌어올리고 있다. 한번쯤 연구해 봐라. 아주 쪼끔 본 관점에선...... \"짱이다\"
부왘부왘 좋은정보 가르쳐주져서 감사합니다
blitz에 역행렬 없을텐데.. LU decomposition이라던가 좀 찾아봐. 기본적인 선형대수만 좀 할 줄 알면 이해하기 어렵지 않을겨
오오오 위에 제가 쓴 시간복잡도 2^n 넘어가는 미친알고리즘보다 좋은거같아요 좀더 알아봐야지
안하긴 개뿔 뭘 안해, 저수준 수학라이브러리라 하기 나름인것을.
ㅋㅋㅋ 그런식으로 말할거면 그냥 C++로 만들으라는거랑 뭐가 다르냐
가우스-조던 소거법으로 임의의 nxn 정사각행렬의 역행렬 구하는 프로그램은 만들어놨는데, 속도는 모르겠음.
그레 넌 처음부터 blitz 라이브러리 짜라 ㅋ 난 있는거 쓸테니 ㅋ
일단 16x16 행렬 입력하기가 귀찮다능...
에휴