# Task_04
## Mảng hai chiều( ma trận):
**1. Lý thuyết:**
- Mảng 2 chiều là một mảng của các mảng 1 chiều. Mảng 2 chiều có cách lưu trữ các phần tử giống như một bảng.
- Ma trận là cấu trúc dữ liệu hai chiều, trong đó các số được sắp xếp thành các hàng và cột.
**2. Ma trận trong Python**
- Python không có kiểu xây dựng riêng dành cho ma trận, vậy nên có thể biểu diễn ma trận dưới dạng một Nested list, có thể hiểu Nested list là dạng danh sách lồng ghép, nghĩa là một list xuất hiện với vai trò là phần tử của một list khác.
vd: A = [[1, 4, 5], [-5, 8, 9]]
```
A = [[1, 4, 5, 12], [-5, 8, 9, 0], [-6, 7, 11, 19]]
print("A =", A)
print("A[1] =", A[1])
print("A[1][2] =", A[1][2])
print("A[0][-1] =", A[0][-1])
column = [];
for row in A: column.append(row[2])
print("Cột thứ 3 =", column)
```
output:
```
A = [[1, 4, 5, 12], [-5, 8, 9, 0], [-6, 7, 11, 19]]
A[1] = [-5, 8, 9, 0]
A[1][2] = 9
A[0][-1] = 12
Cột thứ 3 = [5, 9, 11]
```
hoặc có thể ->Sử dụng **NumPy** cho ma trận
- NumPy là thư viện được viết nhằm phục vụ cho việc tính toán khoa học, hỗ trợ nhiều kiểu dữ liệu đa chiều giúp cho việc tính toán, lập trình, làm việc với các hệ cơ sở dữ liệu cực kì thuận tiện.
- Để tạo một ma trận ta có thể sử dụng ndarray (viết gọn là array) của NumPy
- Array này là một đối tượng mảng đa chiều thuần nhất tức là mọi phần tử đều cùng 1 kiểu.
Input:
```
import numpy as np
a = np.array([1, 2, 3])
print(a)
print(type(a))
```
Output:
```
[1, 2, 3]
print(type(a))
<class 'numpy.ndarray'>
```
-Cách tạo array của NumPy
Mảng số nguyên, số thực, số phức (integer, float, complex)
```
import numpy as np
A = np.array([[1, 2, 3], [3, 4, 5]])
print(A)A = np.array([[1.1, 2, 3], [3, 4, 5]])
print(A)A = np.array([[1, 2, 3], [3, 4, 5]], dtype = complex)
print(A)
```
Output:
```
[[1 2 3] [3 4 5]]
[[1.1 2. 3. ] [3. 4. 5. ]]
[[1.+0.j 2.+0.j 3.+0.j]
[3.+0.j 4.+0.j 5.+0.j]]
```
Mảng giá trị mặc định (0 và 1)
iInput:
```
import numpy as np
A = np.zeros( (2, 3) )
print(A)
B = np.ones( (1, 5) )
print(B)
```
Output:
```
[[0. 0. 0.] [0. 0. 0.]]
[[1 1 1 1 1]]
```
Sử dụng **arange()** và **shape()**
Input:
```
import numpy as np
A = np.arange(4)
print('A =', A)
B = np.arange(12).reshape(2, 6)
print('B =', B)
```
Output:
```
A = [0 1 2 3]
B = [[ 0 1 2 3 4 5] [ 6 7 8 9 10 11]]
```
**Xuất các phần tử, cột, dòng của ma trận**
-Phần tử của ma trận
Input:
```
import numpy as np
A = np.array([[1, 4, 5, 12], [-5, 8, 9, 0], [-6, 7, 11, 19]])
print("A[0][0] =", A[0][0])
print("A[1][2] =", A[1][2])
print("A[-1][-1] =", A[-1][-1])
```
Output:
```
A[0][0] = 1
A[1][2] = 9
A[-1][-1] = 19
```
-Dòng của ma trận
Input:
```
import numpy as np
A = np.array([[1, 4, 5, 12], [-2, 8, 6, 14], [-1, 5, 10, 22]])
print("A[0] =", A[0])
print("A[2] =", A[2])
print("A[-1] =", A[-1])
```
Output:
```
A[0] = [1, 4, 5, 12]
A[2] = [-1, 5, 10, 22]
A[-1] = [-1, 5, 10, 22]
```
Xuất các cột của ma trận
Input:
```
import numpy as np
A = np.array([[1, 4, 5, 12], [-2, 8, 6, 14], [-1, 5, 10, 22]])
print("A[:,0] =",A[:,0])
print("A[:,3] =", A[:,3])
print("A[:,-1] =", A[:,-1])
```
Lát cắt của Ma trận
Input:
```
import numpy as np
A = np.array([1, 3, 5, 7, 9, 7, 5])
print(A[2:5])
print(A[:-5])
print(A[5:])
print(A[:])
print(A[::-1])
```
Output:
```
[5, 7, 9]
[1, 3]
[7, 5]
[1, 3, 5, 7, 9, 7, 5]
[5, 7, 9, 7, 5, 3, 1]
```
***Một số bài tập phép toán với ma trận**
Cộng 2 ma trận (cùng cấp m x n)
```
import numpy as np
A = np.array([[2, 4], [5, -6]])
B = np.array([[9, -3], [3, 6]])
C = A + B
print(C)
```
Output:
```
[[11 1] [ 8 0]]
```
Nhân 2 ma trận
-là phép lấy tổng của tích từng phần tử của hàng tương ứng với cột tương ứng(ma trận trước phải có số cột bằng số hàng của ma trận sau, vd: a(2 x 3).b(3.3))
Input:
```
import numpy as np
A = np.array([[3, 6, 7], [5, -3, 0]])
B = np.array([[1, 1], [2, 1], [3, -3]])
C = a.dot(B)
print(C)
```
Output:
```
[[ 36 -12] [ -1 2]]
```
Chuyển vị ma trận
Input:
```
import numpy as np
A = np.array([[1, 1], [2, 1], [3, -3]])
print(A.transpose())
```
Output:
```
[[ 1 2 3] [ 1 1 -3]]
```
## Chuỗi
Lý thuyết là kiểu dữ liệu bất biến trong python, có nghĩa là một khi chuỗi được tạo, chúng không thể thay đổi.
Kiểu dữ liệu chuỗi (String) trong Python là một trong các kiểu phổ biến nhất trong Python. Chuỗi ký tự trong python được bao quanh bởi dấu ngoặc kép đơn hoặc dấu ngoặc kép. Python coi các lệnh trích dẫn đơn và kép là như nhau
**Nhập chuỗi**
Nhập 1 chuỗi
Có thể nhập chuỗi python bằng hàm **input()**:
```
val = input('Enter your name: ')
print('You are', val)
```
Output:
```
Enter your name: anh
>> You are anh
```
Nhập nhiều chuỗi trong python
Input:
```
val_1 = input('Nhập chuỗi thứ 1: ')
val_2 = input('Nhập chuỗi thứ 2: ')
val_3 = input('Nhập chuỗi thứ 3: ')
print(val_1,val_2,val_3)
```
Output:
```
Nhập chuỗi thứ 1: Tự học
Nhập chuỗi thứ 2: lập trình
Nhập chuỗi thứ 3: Python
>> Tự học lập trình Python
```
hoặc có thể quyết định số lần nhập dữ liệu bằng cách sử dụng vòng lặp for và lưu các chuỗi nhập từ bàn phím vào một **tuple** hoặc một **list**:
Input:
```
num = 3
mytuple = ()
for i in range(3):
val = input('Enter value: ')
mytuple += ( val,)
print(mytuple)
```
Output:
```
>> Enter value: a
>> Enter value: b
>> Enter value: c
>> ('a', 'b', 'c')
```
Sử dụng hàm **split()**
Input:
```
x, y = input("Enter two values: ").split()
print("First number is: ", x)
print("Second number is: ", y)
a, b = input("Enter two values: ").split()
print("First number is {} and second number is {}".format(a, b))
x = list(map(int, input("Enter multiple values: ").split()))
print("List of numbers: ", x)
```
Output:
```
Enter two values: 2 3
Number of the first: 2
Number of the second: 3
Enter two values: 9 8
First number is 9 and second number is 8
Enter multiple values: 7 8 1 2 3
List of numbers: [7, 8, 1, 2, 3]
```
**Xuất chuỗi**
Cú pháp:
```
print(value(s), sep= ‘ ‘, end = ‘\n’, file= sys.stdout, flush=False)
```
Input:
```
print("Welcome to \n Gochocit.com")
print("Hello!", end= "**")
print("Welcome to Gochocit.com")
b = "to"
print("Welcome", b, "Gochocit.com")
print("Welcome", b, "Gochocit.com", sep="-")
x = 5
print("x =", x)
```
Output:
```
Welcome to
Gochocit.com
Hello!**Welcome to Gochocit.com
Welcome to Gochocit.com
Welcome-to-Gochocit.com
x = 5
```
hoặc
Input:
```
x = 5; y = 10
print('The value of x is {} and y is {}'.format(x,y))
print('I love {0} and {1}'.format('bread','butter'))
print('I love {1} and {0}'.format('bread','butter'))
```
Output:
```
The value of x is 5 and y is 10
I love bread and butter
I love butter and bread
```
hoặc kết hợp cùng toán tử
Input:
```
x = 12.3456789
print('The value of x is %3.2f' %x)
print('The value of x is %3.4f' %x)
y = 5
name = "Gochocit.com"
print("num = %d" %y);
print("My name is %s" %name);
```
Output:
```The value of x is 12.35
The value of x is 12.3457
num = 5
My name is Gochocit.com
```
**Một số hàm xử lý chuỗi trong Python**
**Capitalize()**-> in hoa chữ cái đầu tiên
Input:
```
string = "hehe"
print(string.capitalize());
```
Output:
```
Hehe
```
**Upper()**-> được sử dụng để viết hoa toàn bộ chuỗi.
Input:
```
a = "xin chao"
print(a.upper())
```
Output:
```
XIN CHAO
```
**Lower()**-> viết thường toàn bộ chuỗi
Input:
```
a = "Xin Chao"
print(a.lower())
```
Output:
```
xin chao
```
**Count()**-> đếm xem trong chuỗi có bao nhiêu ký tự cần tìm
Input:
```
string = "hello"
print(string.count('o'))
```
Output:
```
1
```
**split()**-> cắt ra một chuỗi dựa trên một ký tự phân tách được chỉ định.
Input:
```
a = "Xin, Chao"
print(a.split(","))
```
Output:
```
[‘Xin’, ‘ Chao’]
```
## Caesar Cipher
Trong mật mã học, Mật mã Caesar (hay còn được gọi là Mật mã của Caesar, Mật mã chuyển vị, Mã của Caesar hay Chuyển vị Caesar) là một trong những kỹ thuật mã hóa đơn giản và phổ biến nhất. Đây là một dạng mật mã thay thế, trong đó mỗi ký tự trên văn bản thô sẽ được thay bằng một ký tự khác, có vị trí cách nó một khoảng xác định trong bảng chữ cái. Ví dụ với độ dịch chuyển là 3, D sẽ trở thành A, E sẽ trở thành B.
Mã hóa dịch vòng caesar
P=K=C=Z
= (x+k) mod n
= (x-k) mod n
vd:
K=14
Y= QHTQFMHC => giải mã dữ liệu theo mã dịch vòng Caesar
->k=14 n=26 Y= QHTQFMHC = {16, 7, 19, 16, 5, 12, 7, 2}
x={2, 19, 5, 2, 17, 24, 19, 14}
X= CTFCRYPTO
## Substitution Cipher
-Mật mã thay thế là một phương pháp mã hóa trong đó các đơn vị của văn bản rõ được thay thế bằng văn bản mật mã , theo một cách xác định, với sự trợ giúp của một khóa; "đơn vị" có thể là các chữ cái đơn lẻ (phổ biến nhất), các cặp chữ cái, bộ ba chữ cái, hỗn hợp của các chữ cái trên, v.v. Người nhận giải mã văn bản bằng cách thực hiện quá trình thay thế nghịch đảo để trích xuất thông điệp gốc.
- Sơ đồ hệ mật mã thay thế được định nghĩa như sau:
S = (P, C, K, E, D)
Trong đó P = C = Z26 , K là tập hợp tất cả các hoán vị trên Z26, các hàm lập mã và giải mã được cho bởi:
E(p, k) = k(p )
D(c, k) = k-1 (c)
trong đó k() ∈ K là một phép hoán vị trên tập Z26.
Ví dụ 1: với khóa k = XNYAHPOGZQWBTSFLRCVMUEKJDI thì ta sẽ có sơ đồ lập và giải mã như sau:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
X N Y A H P O G Z Q W B T S F L R C V M U E K J D I
khi đó "HELLO" được mã hóa thành "GHWWS"
Ví dụ 2: với khóa k = WORlDCUP thì ta sẽ có sơ đồ lập và giải mã như sau:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
W O R L D C U P A B E F G H I J K M N Q S T V X Y Z
khi đó "HELLO" được mã hóa thành "PDFFI"
Mật mã Vigenère là một phương pháp mã hóa văn bản bằng cách sử dụng xen kẽ một số phép mã hóa Caesar khác nhau dựa trên các chữ cái của một từ khóa. Nó là một dạng đơn giản của mật mã thay thế dùng nhiều bảng chữ cái.
## Vigenere Cipher
- Mật mã Vigenère là một phương pháp mã hóa văn bản bằng cách sử dụng xen kẽ một số phép mã hóa Caesar khác nhau dựa trên các chữ cái của một từ khóa. Nó là một dạng đơn giản của mật mã thay thế dùng nhiều bảng chữ cái.

- Trong phép mã hóa Caesar, mỗi ký tự của bảng chữ cái được dịch đi một khoảng nhất định, ví dụ với bước dịch là 3, A trở thành D, B trở thành E... Mật mã Vigenère là sự kết hợp xen kẽ vài phép mã hóa Caesar với các bước dịch khác nhau.
- Để mã hóa, ta dùng một hình vuông Vigenère (hình bên). Nó gồm 26 hàng, mỗi hàng dịch về bên trái một bước so với hàng phía trên, tạo thành 26 bảng mã Caesar. Trong quá trình mã hóa, tùy theo từ khóa mà mỗi thời điểm ta dùng một dòng khác nhau để mã hóa văn bản.
Phương pháp:
- Trước hết ta sẽ nhân chuỗi từ khóa lên để nó có cùng độ dài với chuỗi cần mã hóa:
- Khi này ta sẽ sử dụng bảng mã hóa như sau: bắt đầu từ trái qua phải, lấy ký tự của key làm dòng, ký tự của chuỗi cần mã hóa là cột và dóng vào trong bảng mã ta được một ký tự, ký tự đó chính là ký tự đã được mã hóa
Ví dụ:
Văn bản: HAVEANICEDAY
Từ khóa: HAPPYHAPPYHA
Bản mã: OAKTYUIRTBHY