1. int, float 등은 숫자 입력이지만

    ? (물음표) 키워드를 이용해서 명시적으로 null 값을 줄 수 있습니다.

 

2. ?연산자로 null값이면 실행되지 않도록 조건문 대신 사용할 수 있습니다.

 

3. ?? 두개를 통해 null 값이면 다른 값으로 설정합니다.

 

코드가 짧아지는 장점이 있습니다.

하지만 무분별하게 사용하게 되면 가독성을 헤치게 됩니다.

using System;
using System.Collections;

namespace ConsoleApp
{
    class Program
    {
        public static void Main(string[] args)
        {
            int? a = null;
            Console.WriteLine("a의 값 {0}", a);
            float? b = null;
            Console.WriteLine("b의 값 {0}", b);


            ArrayList arraylist = null;
            arraylist?.Add(30); //arraylist가 null이 아니면 Add(30)
            /*
            if (arraylist == null)
            {
                arraylist.Add(30);
            }
            */

            Console.WriteLine(arraylist?[0]); //null 이지만 오류가 나지 않습니다.

            a = a ?? 20; //a가 null이면 20
            b = b ?? 30.9f; //b가 null 이면 30.9f
            Console.WriteLine("a = {0}, b = {1}", a, b);
        }
    }
}

 

[실행 결과] null은 공백으로 출력됩니다.

 

1. 바이너리 파일로 저장하고 읽어오는 코드입니다.

 여러 타입을 저장할 수 있는데 읽어올 때 반드시 저장된 순서대로 읽어줘야 됩니다.

 (문자열은 앞에 문자열의 길이 + 문자열이 저장되어 해당 길이만큼 읽어옵니다.)

using System;
using System.IO; //...Stream

namespace ConsoleApp
{
    class Program
    {
        public static void Main(string[] args)
        {
            //바이너리 파일 생성 및 저장
            FileStream fs = new FileStream("Test.bin", FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);

            string input1 = Console.ReadLine();
            int input2 = Convert.ToInt32(Console.ReadLine());
            float input3 = Convert.ToSingle(Console.ReadLine());

            bw.Write(input1); //string
            bw.Write(input2); //int
            bw.Write(input3); //float

            bw.Close();
            fs.Close();

            //바이너리 파일 읽어오기
            FileStream fs2 = new FileStream("Test.bin", FileMode.Open);
            BinaryReader br = new BinaryReader(fs2);

            Console.WriteLine(br.ReadString()); //string
            Console.WriteLine(br.ReadInt32()); //int
            Console.WriteLine(br.ReadSingle()); //float

            br.Close();
            fs2.Close();
        }
    }
}

 

입력을 받고 읽어온 모습
저장된 데이터

 

2. StreamReader/StreamWriter 를 이용한 모습입니다. 문자열 그대로 저장이 됩니다.

using System;
using System.IO; //...Stream

namespace ConsoleApp
{
    class Program
    {
        public static void Main(string[] args)
        {
            StreamWriter sw = new StreamWriter("Test.dat");
            
            for (int i = 0; i < 5; ++i) //5개의 입력
            {
                sw.WriteLine(Console.ReadLine());
            }

            sw.Close();

            StreamReader sr = new StreamReader("Test.dat");

            while (!sr.EndOfStream) //sr.ReadLine() == null인 경우입니다.
            {
                Console.WriteLine(sr.ReadLine());
            }

            sr.Close();
        }
    }
}

5개의 입력을 받고 다시 출력해준 모습
저장된 데이터

 

보안적인 측면은 바이너리 코드가 읽기가 어려워지기 때문에 더 좋습니다.

아니면 암호화나 해시를 하는 방법을!

https://www.acmicpc.net/problem/3197

 

3197번: 백조의 호수

입력의 첫째 줄에는 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1500. 다음 R개의 줄에는 각각 길이 C의 문자열이 하나씩 주어진다. '.'은 물 공간, 'X'는 빙판 공간, 'L'은 백조가 있는 공간으로 나타낸다.

www.acmicpc.net

 

물(.) 옆에 있는 빙판(X)은 하루가 지날 때 마다 사라집니다.

백조(L) 두 마리가 며칠 뒤에 만날 수 있는가를 탐색하는 문제입니다.

 

제가 한 풀이는 이렇습니다. 우선 분리 집합을 통해 그룹화 시켜주었습니다.

( 분리 집합(Disjoint Set) 을 잘 모르시는 분은 나중에 다시 글을 올려 링크해 두겠습니다. )

 

1. 모든 지형을 탐색합니다. 물이나 백조인 곳을 기점으로 번호를 매겨 DFS 탐색을 해줍니다.

2.  .이라면 계속 탐색하고, X를 만나면 탐색을 중지하고 큐에 넣어줍니다.

 

 

3. 백조 두 마리가 처음부터 같은 그룹에 있을 수 있습니다. 이를 확인하여 처리해 줍니다.

 

4.

 4-1. X 위치에서 주변을 탐색하고 분리 집합 (parent)을 사용하여 같은 그룹으로 만들어 줍니다.

bird[1] = 3 에서 1로 변경되었습니다.

 4-2. bird[0] 과 bird[1] 이 같으면 백조는 서로 만나게 된 상태입니다.

      만났다면 day를 출력

      만나지 못했다면 day를 1 증가 시키고 4-3으로 갑니다.

 

 4-3. 다시 주변 X를 queue에 넣어주며 4를 반복합니다.

 

 

 

 

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

queue<pair<int, int>> q;
vector<int> bird;
vector<int> parent;

char input[1500][1501];
int visited[1500][1500];
int dir[4][2] = 
{
	{1, 0},
	{0, 1},
	{-1, 0},
	{0, -1}
};

void DFS(int startRow, int startCol, int r, int c, int group)
{
	if (input[startRow][startCol] == 'L')
	{
		bird.push_back(group); //새가 어느 그룹에 속해있는지 저장해둡니다.
	}

	for (int i = 0; i < 4; ++i)
	{
		int nextRow = startRow + dir[i][0];
		int nextCol = startCol + dir[i][1];

		if (nextRow < 0 || r <= nextRow ||
			nextCol < 0 || c <= nextCol ||
			visited[nextRow][nextCol] > 0)
		{
			continue;
		}
		
		visited[nextRow][nextCol] = group;

		if (input[nextRow][nextCol] == 'X')
		{
			q.push(make_pair(nextRow, nextCol));
		}
		else
		{
			DFS(nextRow, nextCol, r, c, group);
		}
	}
}

int GetParent(int p)
{
	if (parent[p] == p)
	{
		return p;
	}

	return parent[p] = GetParent(parent[p]);
}

int SetParent(int from, int to)
{
	return parent[from] = parent[to];
}

//테스트 출력용
void PrintState(int r, int c, int day)
{
	cout << endl << "day : " << day << endl;

	for (int i = 0; i < r; ++i)
	{
		for (int j = 0; j < c; ++j)
		{
			cout << GetParent(visited[i][j]) << "";
		}
		cout << endl;
	}

	cout << "parent : " << endl;

	for (int i = 1; i < parent.size(); ++i)
	{
		cout << "[" << i << "] " << parent[i] << " ";
	}

	cout << endl;
}

int main()
{
	int r, c;
	int day = 1;
	int groupId = 1;
	cin >> r >> c;

	parent.push_back(0);
	for (int i = 0; i < r; ++i)
	{
		cin >> input[i];
	}

	for (int i = 0; i < r; ++i)
	{
		for (int j = 0; j < c; ++j)
		{
			if (visited[i][j] > 0)
			{
				continue;
			}

			if (input[i][j] == '.' || input[i][j] == 'L') //탐색 및 그룹화
			{
				visited[i][j] = groupId;
				DFS(i, j, r, c, groupId);
				parent.push_back(groupId);
				groupId++;
			}
		}
	}

	if (GetParent(bird[0]) == GetParent(bird[1])) //이미 만나 있는 상태
	{
		cout << 0 << endl;
		return 0;
	}

	while (!q.empty())
	{
		int size = q.size();

		//4-1
		for (int i = 0; i < size; ++i)
		{
			q.push(q.front());

			int row = q.front().first;
			int col = q.front().second;
			int group = GetParent(visited[row][col]);
			q.pop();

			for (int j = 0; j < 4; ++j)
			{
				int nextRow = row + dir[j][0];
				int nextCol = col + dir[j][1];

				if (nextRow < 0 || r <= nextRow ||
					nextCol < 0 || c <= nextCol || 
					visited[nextRow][nextCol] == 0)
				{
					continue;
				}
				int from = GetParent(visited[nextRow][nextCol]);

				SetParent(from, group);
			}
		}

		//4-2
		PrintState(r, c, day);
		if (GetParent(bird[0]) == GetParent(bird[1]))
		{
			break;
		}
		
		//4-3
		day++;
		for (int i = 0; i < size; ++i)
		{
			int row = q.front().first;
			int col = q.front().second;
			int group = visited[row][col];
			q.pop();

			for (int j = 0; j < 4; ++j)
			{
				int nextRow = row + dir[j][0];
				int nextCol = col + dir[j][1];

				if (nextRow < 0 || r <= nextRow ||
					nextCol < 0 || c <= nextCol ||
					visited[nextRow][nextCol] > 0)
				{
					continue;
				}

				visited[nextRow][nextCol] = group;
				q.push(make_pair(nextRow, nextCol));
			}
		}
	}

	cout << day << endl;
}

https://www.acmicpc.net/problem/2805

 

2805번: 나무 자르기

첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000) 둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M보

www.acmicpc.net

 

n개의 나무 중 m개 이상을 가져갈 수 있는 최소 높이를 구하는 문제입니다.

이분 탐색을 이용한 풀이와 높이를 비교하며 푸는 방법 두 가지가 있습니다.

 

먼저 이분 탐색을 사용한 일반적인 풀이입니다.

(이분 탐색이 left <= right,  left < right 등과 같이 여러 변형이 있고 쓰이는 곳이 달라집니다.

이건 종이에 써가면서 해보는게 좋을거 같네요!)

 

#include <iostream>
#include <algorithm>

using namespace std;

int input[1000000];

int BinarySearch(int n, int m)
{
	int left = 0;
	int right = 1000000000;

	while (left <= right)
	{
		int mid = (left + right) / 2;
		long long sum = 0LL;

		for (int i = 0; i < n; ++i)
		{
			if (input[i] > mid)
			{
				sum += (long long)input[i] - (long long)mid;
			}
		}

		if (sum == m)
		{
			return mid;
		}
		else if (sum > m)
		{
			left = mid + 1;
		}
		else
		{
			right = mid - 1;
		}
	}

	return right;
}

int main()
{
	int n, m;
	int left = 0;
	int right = 0;

	cin.tie(0);
	cin >> n >> m;

	for (int i = 0; i < n; ++i)
	{
		cin >> input[i];
	}

	sort(input, input + n);

	cout << BinarySearch(n, m) << endl;
}

 

다른 방법은 높이를 큰 순서로 나열한 후 잘라가며 원하는 수량을 체크하는 것입니다.

이 방법은 제가 알아낸 것은 아니고 어떤 분의 풀이였던 것 같습니다.

1

 

 

2

 

#include <iostream>
#include <algorithm>

using namespace std;

int input[1000001];

bool compare(int a, int b)
{
	return a > b;
}

int main()
{
	int n, m;
	long long sum = 0;
	int index = 1;
	int cut = 0;

	cin >> n >> m;

	for (int i = 0; i < n; ++i)
	{
		cin >> input[i];
	}

	sort(input, input + n, compare);

	while (sum < m)
	{
		sum += ( (long long)input[index - 1] - (long long)input[index] ) * index;
		index++;
	}

	cut = (sum - m) / (index - 1);
	cout << input[index - 1] + cut << endl;
}

cut을 구하는 것이 핵심인 코드입니다. ㅎㅎ

(이때 index가 배열의 크기를 넘어서지 않기위해 n + 1개 만큼의 배열로 선언해주어야 합니당.)

파일을 통해 데이터를 저장하여 불러오거나 해도 되지만

유니티에는 스크립터블 오브젝트라는 형태로 데이터 저장 및 사용이 가능합니다.

 

using UnityEngine;

[CreateAssetMenu(fileName = "MyEditorData", menuName = "Custom ScriptableObject/MyEditorData")]
public class MyEditorData : ScriptableObject
{
    public string filePath;
}

 

우선 string형 하나만 입력받도록 설정해줍니다. 클래스는 ScriptableObject 를 상속 받기만 하면 됩니다.

생성을 위해 CreateAssetMenu 를 설정해주겠습니다.

fileName : 생성될 파일명

munuName : 메뉴에 나타날 이름입니다.

 

CreateAssetMenu를 통해 해당 이름으로 파일 생성이 가능해졌습니다.

 

 

해당 파일을 클릭하면 Inspector에서 보기 및 편집이 가능합니다.

 

유니티를 껏다켜도 해당 정보는 저장되어 있게 됩니다.

이제 이것을 통해 윈도우 에디터 값들을 저장하며 만들 예정입니다!

using UnityEngine;
using UnityEditor;

public class MyEditor : EditorWindow
{
    private static EditorWindow window;
    private static float width = 600;
    private static float height = 600;

    [MenuItem("CustomWindow/MyEditor")] //상단 메뉴에 추가됩니다.
    public static void Open ()
    {
        window = GetWindow<MyEditor>();

        Rect main = EditorGUIUtility.GetMainWindowPosition(); //전체 화면 크기를 갖고 옵니다.

        window.minSize = window.maxSize = new Vector2(width, height); //시작 사이즈를 width, height로 만들어 주고

        window.minSize = new Vector2(200, 200);
        window.maxSize = new Vector2(main.width, main.height); //제한을 풀어줍니다.

        //window.position에 x, y 좌표와 width, height가 들어있습니다.
        window.position = new Rect((main.width - width) * 0.5f, (main.height - height) * 0.5f, width, height);
    }

    private void OnGUI()
    {
        GUILayout.Label("Hello!");
    }
}

 

[MenuItem("CustomWindow/MyEditor")] 를 통해 메뉴가 상단에 추가 된 모습

 

윈도우 창이 실행 된 모습. 가운데에 위치하게 됩니다. (전체화면으로 한 경우만!)

유니티 에디터에 대해 독학 중인데 엄청난 뻘짓들을 하고 있습니다..

가끔씩 이상한데 꽂혀서 시간을 많이 쓰네요.. ㅠ_ㅠ

 

찾아보면 기능들이 다양하고 많네요 ' - '@

시간이 되면 만져 본 것들을 하나씩 정리해보기!

커스텀 에디터를 만들 때 가장 중요한 항목은 사용자의 확인, 취소에 대한 입력을 받는 것입니다.

그리고 실수로 잘 못 된 버튼을 누르는 것을 방지하거나 무언가 오류가 생길시 알림을 주는 기능도 할 수 있습니다.

 

C#으로 치면 MessageBox 기능이고

유니티에서는 UnityEditor.EditorUtility.DisplayDialog 를 통해 메시지 출력이 가능합니다.

 

에디터 모드에서도 가능하지만 실시간 게임 중에도 출력이 가능하기에 우선

플레이 버튼 시 메시지가 뜨도록 MonoBehaviour에 작성하여 실행시켜보았습니다.

 

파라미터 개수에 따라 확인만 가능하거나 취소까지 가능하며

해당 결과를 bool 값으로 받을 수 있습니다.

using UnityEngine;
using UnityEditor;

public class ShowMessage : MonoBehaviour
{
    void Start()
    {
        bool result = EditorUtility.DisplayDialog("제목", "메시지", "확인", "취소");

        if (result)
        {
            EditorUtility.DisplayDialog("클릭 결과", "확인 메시지가 클릭되었습니다.", "확인");
        }
        else
        {
            EditorUtility.DisplayDialog("클릭 결과", "취소 메시지가 클릭되었습니다.", "확인");
        }
    }
}

 

초기 메시지

 

https://ko.wikipedia.org/wiki/RSA_%EC%95%94%ED%98%B8

 

RSA 암호 - 위키백과, 우리 모두의 백과사전

RSA 암호는 공개키 암호시스템의 하나로, 암호화뿐만 아니라 전자서명이 가능한 최초의 알고리즘으로 알려져 있다. RSA가 갖는 전자서명 기능은 인증을 요구하는 전자 상거래 등에 RSA의 광범위한

ko.wikipedia.org

위의 내용을 참고하였습니다.

 

RSA 방식 간단한 소개

공개키 <e, n>

개인키 <d, n>

암호화 작업 복호화 작업
메시지^d % n 메시지^e % n
메시지^e % n 메시지^d % n

d와 e는 서로 암호화 및 복호화에 필요하며 e만 공개하고

d는 개인키로 숨겨둬야 됩니다.

 

공개키와 개인키를 구하는 방법을 살펴보겠습니다.

사실 엄청나게 큰 소수를 선택하여 d를 계산해내지 못하게 해야되지만

지금은 작은 숫자를 통해 동작을 살펴보았습니다. 

 

소수 2개 (p, q)를 입력받습니다.  p = 23, q = 29

n = p * q 로 정의해줍니다. (n = 667)

오일러피 함수 (n) = (23 - 1) * (29 - 1) 을 얻고,

 오일러피 함수 결과와 서로소인 값을 하나 선택합니다. 해당 값이 공개키 e 값이 됩니다. e = 307을 선택하였습니다.

 

개인키 d를 구합니다. d는 e * d % n == 1 이 되는 d값을 구해주면 됩니다.

d = 2155를 선택하였습니다.

 

공개키와 개인키가 만들어졌습니다. 이제 메시지를 작성해봅니다.

이 때 n이 충분히 크지 않다면..! 아래 결과 내용을 읽어보시길..

"암호화할 메시지 입니다~~ !@#$$% 1234567" 까지가 메시지 입니다.

 

암호화 한 후 출력, 이 후 다시 복호화한 작업입니다.

 

 

기본 개념

 

1. 공개키와 개인키는 서로 암호화/복호화 작업에 필요한 키입니다.

2. 공개키 e는 외부에 공개하지만 d는 개인키로 알려져선 안됩니다. d는 복호화 작업에 쓰이는 중요한 키입니다.

 

키 생성 방법

1. 소수 2개 (p, q)를 고릅니다.

2. 둘의 곱 n = p * q 를 얻습니다.

3. 오일러phi (n) 값을 구합니다. n = 소수 * 소수 이므로

   eulerPhi = (p - 1) * (q - 1) 를 얻습니다.

(오일러피 함수 : 

https://ko.wikipedia.org/wiki/%EC%98%A4%EC%9D%BC%EB%9F%AC_%ED%94%BC_%ED%95%A8%EC%88%98)

 (오일러피 함수 (n)은 n보다 작고 n과 서로소인 (서로소: 최대 공약수가 1인 숫자) 숫자의 개수를 의미합니다.

오일러피 함수의 성질에 따라 두 소수는 (p - 1) * (q - 1) 로 정의됩니다.)

  •  phi(소수) = 소수 - 1
  •  phi(소수1 * 소수2) = phi(소수1) * phi(소수2) = (소수1 - 1) * (소수2 - 1)

4. eulerPhi 보다 작고 eulerPhi와 서로소인 정수 e를 찾아 선택합니다. (e가 공개키가 됩니다.)

5. d * e % eulerPhi == 1 인 d를 찾습니다. (d가 개인키가 됩니다.)

6. 최종적으로 키가 생성됩니다.

 <e, n> 공개키,    <d, n> 개인키

 

암호화 방법

 메시지를 e번 제곱해주고 n으로 나눈 나머지를 얻습니다.

 

복호화 방법

 메시지를 d번 제곱해주고 n으로 나눈 나머지를 얻습니다.

 

주의사항) n은 우리가 사용하는 문자 값보다 커야됩니다.

 n이 'A' (65) 보다 작다면 A라는 의미를 잃어버리기 때문입니다.

 

프로그램에선 숫자가 너무 커지므로 제곱할 때마다 n으로 나눠주고 있습니다.

코드가 좀 길어서 제가 다시 볼지 모르겠습니다 ㅋㅋ;

 

코드 흐름

1. InitPrime() : 에라토스테네스의 체를 통해 notPrime배열에 소수를 구해두기

2. 소수 p, q를 입력받기

3. 오일러피 값을 구합니다. eulerPhi = (p - 1) * (q - 1)

4. GetRelativePrime() : eulerPhi 에 서로수인 숫자를 구합니다. (최대공약수를 찾기 위해 GCD 가 쓰입니다)

5. 공개키 e 입력 받기

6. FindPrivateDKey() : 개인키 후보를 찾습니다.

7. 개인키 d 입력 받기

8. 문자열 입력

9. Encryption() : 암호화 및 출력

 (여기서 char 배열에서 int 배열로 바꿔서 저장합니다.

 char는 1byte (=8bit) 최대 255까지밖에 표현되지 않아 값을 잃어버리기 때문입니다.)

10. Decryption() : 암호를 복호화하여 출력

 

#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

const int MaxSize = 10000;
const int Size = 100;
const int LineLength = 14;

bool notPrime[MaxSize];
bool relativePrime[MaxSize]; //서로소
char input[100];
int encryptToInt[100];

vector<long long> dList;

void InitPrime()
{
	notPrime[0] = notPrime[1] = true;

	for (int i = 2; i * i <= MaxSize; ++i)
	{
		if (notPrime[i])
		{
			continue;
		}

		for (int j = i * i; j <= MaxSize; j += i)
		{
			notPrime[j] = true;
		}
	}
}

void PrintPrime(int enterLine, int size)
{
	printf("====소수 목록====\n");
	int line = 0;
	for (int i = 2; i < Size; ++i)
	{
		if (notPrime[i])
		{
			continue;
		}

		printf("%3d ", i);
		line++;

		if (line >= enterLine)
		{
			line = 0;
			printf("\n");
		}
	}
}

int GCD(int a, int b) //Greatest Common Divisor 최대 공약수 찾기
{
	while (b != 0)
	{
		int c = a % b;
		a = b;
		b = c;
	}

	return a;
}

void GetRelativePrime(int enterLine, int phi)
{
	int line = 0;
	for (int i = 1; i < phi; ++i)
	{
		if (GCD(i, phi) == 1)
		{
			line++;
			printf("%3d ", i);
			relativePrime[i] = true;
			
			if (line >= enterLine)
			{
				line = 0;
				printf("\n");
			}
		}
	}
}

void FindPrivateDKey(int e, int eulerPhi, int many)
{
	for (long long d = 1; dList.size() < many; ++d)
	{
		if (d * e % eulerPhi == 1)
		{
			dList.push_back(d);
			printf("[%d]번째 가능한 개인키 d = %lld [ %lld * %d %% %d = 1 ]\n", dList.size(), d, d, e, eulerPhi);
		}
	}
}

int Pow(int value, int e, int n)
{
	int v = value;
	for (int i = 1; i < e; ++i)
	{
		v = v * value % n;
	}
	return v;
}

void Encryption(int e, int n)
{
	char encryptForPrint[100] = { 0 };
	int length = strlen(input);

	for (int i = 0; i < length; ++i)
	{
		int value = Pow(input[i], e, n);

		//char는 1바이트로 8bit, 최대 2^8 (256) 까지밖에 표현이 불가능하여
		//값이 256을 넘으면 오버플로우 발생
		encryptToInt[i] = value; 
		encryptForPrint[i] = value;
	}

	printf("%s\n", encryptForPrint);
}

void Decryption(int d, int n)
{
	char decryptForPrint[100] = { 0 };
	int length = strlen(input);

	for (int i = 0; i < length; ++i)
	{
		decryptForPrint[i] = Pow(encryptToInt[i], d, n);
	}
	printf("%s\n", decryptForPrint);
}

int main()
{
	int p, q, n, e;
	long long d;

	InitPrime();
	PrintPrime(LineLength, Size);
	printf("\n\n두 개의 소수를 입력하세요.\n");
	
	while (true)
	{
		scanf("%d %d", &p, &q);
		if (notPrime[p] || notPrime[q])
		{
			printf("\n소수를 다시 입력하세요.\n");
			continue;
		}

		break;
	}

	n = p * q; //[중요] n보다 작은 값들에 대해서만 암호화가 가능하다!!! % n 으로 나누어주기 때문이다.

	int eulerPhi = (p - 1) * (q - 1);
	printf("\n오일러 피 함수 값 %d * %d = %d\n", (p - 1), (q - 1), eulerPhi);
	printf("====%d와 서로수인 수====\n", eulerPhi);
	GetRelativePrime(LineLength, eulerPhi);
	printf("\n\n");

	while (true)
	{
		scanf("%d", &e);
		if (relativePrime[e])
		{
			break;
		}
		else
		{
			printf("\n서로수인 수를 입력해야됩니다.\n");
		}
	}

	FindPrivateDKey(e, eulerPhi, 5); //5개를 구해보자
	printf("\n개인키를 입력하세요.\n");

	while (true)
	{
		scanf("%lld", &d);
		
		bool isContain = false;

		for (int i = 0; i < dList.size(); ++i)
		{
			if (dList[i] == d)
			{
				isContain = true;
				break;
			}
		}

		if (isContain)
		{
			break;
		}
		else
		{
			printf("\n올바른 개인키를 입력해야 됩니다.\n");
		}
	}

	printf("\n\n 공개키 [e = %d, n = %d], 개인키 [d = %lld, n = %d]\n\n", e, n, d, n);

	printf("100문자 이내로 평문을 작성해보세요.\n");
	printf("(단 n의 크기가 해당 문자를 나타내는 숫자보다 작다면 변환값을 잃게 됩니다.)\n");
	printf("ex) 'A' = 65, n = 42라면 65값을 잃게 됩니다.\n\n");

	getchar(); //버퍼에 엔터키 제거용
	gets_s(input);

	printf("\n평문을 암호화 합니다.\n");
	Encryption(e, n);

	printf("\n==============================================\n");

	printf("\n평문을 복호화 합니다.\n\n");
	Decryption(d, n);

	return 0;
}

 

https://ko.wikipedia.org/wiki/%EC%9C%A0%ED%81%B4%EB%A6%AC%EB%93%9C_%ED%98%B8%EC%A0%9C%EB%B2%95

 

유클리드 호제법 - 위키백과, 우리 모두의 백과사전

유클리드 호제법(-互除法, Euclidean algorithm) 또는 유클리드 알고리즘은 2개의 자연수 또는 정식(整式)의 최대공약수를 구하는 알고리즘의 하나이다. 호제법이란 말은 두 수가 서로(互) 상대방 수를

ko.wikipedia.org

 

유클리드 호제법으로도 불립니다.

GCD는 굉장히 간단한 코드라서 외워서 쓸 정도인데 막상 안보고 구현하려니 헷갈려서

유도 방식을 직접 써서 생각해보게 되었습니다.

 

GCD (21, 12)     (참고로 GCD(12, 21)을 해도 12 % 21 = 12로 21 % 12로 바뀜)

21 % 12 = 9        
    12 % 9 = 3    
        9 % 3 = 0

GCD (21, 12) = 3

 

위의 숫자들을 그대로 가져와서 써주면 됩니다.

#include <iostream>

using namespace std;

int GCD(int a, int b)
{
	while (b != 0)
	{
		int c = a % b;
		a = b;
		b = c;
	}

	return a;
}

int main()
{
	cout << GCD(21, 12);
}

 

추가적으로 a와 b의 최대 공배수를 구하는 방법은

a * b / GCD(a, b) 로 할 수 있습니다.

 

ex)

8 과 10의 최소 공배수 구하기

8 * 10 / GCD(8, 10)   ( GCD(8, 10) = 2 )

8 * 10 / 2 = 40

클록을 통해 현재 경과한 시간을 알 수 있습니다.

아래 코드에서 5초 동안 돌아가며 i가 증가되는 값을 볼 수 있습니다.

 

#include <iostream>
#include <ctime>

using namespace std;

int main()
{
	clock_t start = clock(); //ms 단위를 반환 합니다. 1s == 1000ms
	int i = 0;
	int second = 0;

	while (second < 5)
	{
		clock_t end = clock();
		i++;
		if (end - start >= 1000)
		{
			second++;
			start = end;
			cout << second << "초 경과 i 값은 " << i << endl;
		}
	}
}

 

실행 결과

 

+ Recent posts