January 20, 2013

Bài tập NMCNTT1 - LaTeX

Đây là bài tập LaTeX của mình. Bạn nào cần tham khảo thì hãy vào link này.

November 28, 2012

NMCNTT1 - Các bài tập đã làm

Mình đã up những bài tập NMCNTT1 đã làm lên dropbox. Bạn nào cần xem thì hãy vào link:
BT NMCNTT1 - Duy Bao

November 25, 2012

ĐỒ ÁN MÔN HỌC NM CNTT1 - BÀI 3

ĐỒ ÁN MÔN HỌC NM CNTT1
LỚP CỬ NHÂN TÀI NĂNG KHÓA 2012

Giảng viên ra đề:
ThS. Trương Phước Hưng

Bài 3: Tính F(x)
Cho hàm F(x), x ≥ 0 được định nghĩa như sau:
F(x) = x, nếu x ≤ 9
F(x) = F(S(x)), nếu x > 9
Trong đó S(x): tổng các chữ số của x.
Yêu cầu: Hãy viết chương trình tính F(n!), với 1 <= n <= 500.

Bài làm
-         Nhận xét ban đầu:
o   Ta cần phải tìm F(500!). 500! là một số hết sức lớn, nằm ngoài khả năng lưu trữ của các kiểu dữ liệu. Vậy ta cần tìm cách tính hàm F mà không cần phải tính n!.
o   Từ công thức đề bài, không khó để thấy kết quả luôn là số nguyên không âm bé hơn 10.

-         Trước hết, ta khoan xét đến F(n!) mà hãy xét F(x) với x nguyên dương. Lúc này, hàm F(x) chính là giá trị nhận được khi ta lặp đi lặp lại quá trình cộng các chữ số của x, với lần lặp sau dùng kết quả đã có của lần lặp trước làm dữ liệu đầu vào. Đến đây, ta có thể viết một vài giá trị đầu tiên của dãy F(x) để tìm kiếm quy luật: 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3 ,4 … Không quá khó để thấy qui luật của dãy số này:
o   F(x) = 9 với x chia hết cho 9.
o   F(x) = x % 9 với x không chia hết cho 9. (% là phép chia lấy phần dư).

-         Từ đây, ta có thể dễ dàng tính được F(x). Vậy còn F(n!) thì sao? Với n≥6, ta có n! chia hết cho 9, vậy thì F(n!) sẽ bằng 9. Còn với n<6 thì ta chỉ việc lặp và tính kết quả do khi đó n! hoàn toàn có thể lưu trữ được.

Mã nguồn
#include <iostream>
using namespace std;
void main()
{
 int iN, iFact = 1;
 cout << "Nhap n: ";
 cin >> iN;
 cout << "F(" << iN << "!) = ";

 if (iN > 6) 
  iN = 6;

 for (int i = 2; i <= iN; i++)
  iFact *= i;

 if (iN == 0)
  iFact = 0;

 cout << 1 + ((iFact - 1) % 9) << endl;
}

ĐỒ ÁN MÔN HỌC NM CNTT1 - BÀI 2

ĐỒ ÁN MÔN HỌC NM CNTT1
LỚP CỬ NHÂN TÀI NĂNG KHÓA 2012
Giảng viên ra đề:
ThS. Trương Phước Hưng


Bài 2: Xem công thức tính sau đây (đề thi tuyển sinh cao học ngành KHMT, năm 2011):
  Aver = Σ(ai – Max)2 + Σ(ai – Min)2 + n/2(Max – Min)2

Trong đó Max, Min lần lượt là giá trị lớn nhất, nhỏ nhất của n số thực (được nhập vào từ thiết bị nhập chuẩn) a0, a1, …, an-1.
Chỉ dùng duy nhất 1 vòng lặp (for hoặc while), đề xuất cách thức để nhập n số thực như trên và tính giá trị của biểu thức Aver, xuất kết quả tính ra thiết bị xuất chuẩn. Viết chương trình để minh họa đề xuất đó.
Lưu ý: Phần này sinh viên chưa học về mảng, như vậy vấn đề chính của bài toán này là không thể dùng mảng để lưu giá trị của n số thực nói trên. Như vậy phải đề xuất một giải pháp “thông minh” để nhập và tính toán mà không đưa trước các số thực này vào mảng.

Bài làm
-         Nhận xét ban đầu:
o   Rõ ràng điểm khó nhất bài này là tìm cách giải mà chỉ dùng 1 vòng lặp. Bởi vì với công thức đã cho, ta hoàn toàn có thể giải bằng 2 vòng lặp bằng cách cho vòng lặp thứ nhất nhập số vào và đồng thời tìm Max, Min của dãy số, còn vòng lặp thứ 2 thì tính toán theo công thức.
o   Do đề bài có nói rõ là không dùng mảng, vậy ta sẽ phải dùng 1 vòng lặp vừa nhập, vừa tính toán rồi sau đó in ra kết quả.

-         Theo công thức đề bài, ta phải biết sẵn Max và Min của dãy số ở mỗi lần lặp. Vậy không thể tính thẳng theo công thức này được mà phải biến đổi nó. Cách biến đổi đơn giản nhất chính là bung hằng đẳng thức ra:
o   Aver = Σ(ai – Max)2 + Σ(ai – Min)2 + n/2(Max – Min)2
= Σ(ai2 – 2aiMax + Max2) + Σ(ai2 – 2aiMin + Min2) + n/2(Max – Min)2
= Σai2 – 2MaxΣai + ΣMax2 + Σai2 – 2MinΣai + ΣMin2 + n/2(Max – Min)2
= 2Σai2 – 2(Max + Min)Σai + n(Max2 + Min2) + n/2(Max – Min)2

o   Đến đây, ta thấy rằng mỗi số hạng đều có thể tính độc lập với nhau:
§  2Σai2: dùng vòng for tính tổng ai2 rồi nhân kết quả cho 2.
§  – 2(Max + Min)Σai: dùng vòng for tính tổng ai và lưu Max, Min của dãy số rồi nhân với -2(Max + Min).
§  n(Max2 + Min2): dùng 1 vòng for lưu Max, Min của dãy số, tính Max + Min rồi nhân với n.
§  n/2(Max – Min)2: dùng 1 vòng for lưu Max, Min của dãy số, tính (Max – Min)2 rồi nhân với n/2.

-         Nếu làm như trên ta sẽ cần ít nhất 4 vòng lặp, thế nhưng nếu nhìn kĩ ta sẽ thấy trong một vòng lặp hoàn toàn có thể dùng nhiều biến để lưu trữ và tính toán tất cả các giá trị cần thiết cho cả 4 số hạng trên. Sau đó, khi thoát khỏi vòng lặp, ta sẽ dùng những giá trị đã tìm được để tính ra kết quả như công thức.

Mã nguồn
#include <iostream>
#include <iomanip>
using namespace std;
void main()
{
 int iN;
 double dA, dMin, dMax, dTong = 0, dTongMu2 = 0, dSoHang1, dSoHang2, dSoHang3, dSoHang4, dKetQua;

 cout << "Nhap so phan tu N: ";
 cin >> iN;
 for (int i = 0; i < iN; i++)
 {
  cout << "Nhap phan tu thu " << i + 1 << " :";
  cin >> dA;
  if (i == 0)
  {
   dMin = dA;
   dMax = dA;
  }
  if (dMin > dA) 
   dMin = dA;
  if (dMax < dA)
   dMax = dA;
  dTong += dA;
  dTongMu2 += dA * dA;
 }

 dSoHang1 = 2 * dTongMu2;
 dSoHang2 = -2 * dTong * (dMax + dMin);
 dSoHang3 = iN * (dMax * dMax + dMin * dMin);
 dSoHang4 = 0.5 * iN * (dMax - dMin) * (dMax - dMin);
 dKetQua = dSoHang1 + dSoHang2 + dSoHang3 + dSoHang4;

 cout << "Ket qua bai toan la: " << fixed << setprecision(9) << dKetQua << endl;
}


ĐỒ ÁN MÔN HỌC NM CNTT1 - BÀI 1


ĐỒ ÁN MÔN HỌC NM CNTT1
LỚP CỬ NHÂN TÀI NĂNG KHÓA 2012

Giảng viên ra đề:
ThS. Trương Phước Hưng


Bài 1: Cho số tự nhiên A. Hãy tìm số tự nhiên N nhỏ nhất sao cho N lũy thừa N (nhân N cho chính nó N lần) chia hết cho A. Hãy viết chương trình tìm số N đó và xuất ra màn hình. Trong đó A có giá trị: 1 A 109
Ví dụ:
Số nhập vào là A
Số xuất ra là N
8
4
13
13



Bài làm
-         Nhận xét ban đầu:
o   AA luôn chia hết cho A nên chắc chắn kết quả N ≤ A. Vậy ta có thể lặp tìm N từ 1 đến A, gặp số N nào thoả NN chia hết A thì ta dừng. Nhưng cách làm này gặp 2 vấn đề: NN tăng rất nhanh và nếu lặp từ 1 đến 109 thì chương trình sẽ chạy khá chậm.
o   Do chỉ cần xét NN có chia hết cho A hay không mà không cần quan tâm kết quả này nên ta có thể phân tích N và A ra thừa số nguyên tố để kiểm tra tính chia hết. Như vậy sẽ không lo NN tràn số. Nhưng chương trình vẫn phải duyệt từ 1 đến A nên vẫn chậm.


-         Đầu tiên, ta sẽ phân tích A và N ra tích các thừa số nguyên tố để dễ xét tính chia hết:
A = p1x1 p2x2 … pkxk
N = q1y1 q2y2 … qmxm
=> NN = q1y1*N q2y2*N … qmxm*N

o   Trong cách phân tích này, ta thấy rằng mọi thừa số nguyên tố pi  của A đều phải chứa trong N. Bởi vì nếu không có pi thì tất cả các số nguyên tố qj đều không chia hết cho pi => NN không chia hết cho A. Vậy nếu đặt r = p1p2…pk, ta có N ≥ r. Ngoài ra, để NN chia hết cho A thì mọi số mũ của pi trong NN phải lớn hơn hoặc bằng số mũ của pi trong A. (*)  

-         Vậy N sẽ có dạng: r*t = p1p2… pk* t.
o   Trong trường hợp r ≥ xi i thì ta chỉ cần đặt N = r thì khi đó NN = p1rp2r… pkr => mọi số mũ của pi trong NN đều lớn hơn hoặc bằng số mũ của pi trong A => NN chia hết cho A theo (*).
o   Trong trường hợp ngược lại (tức i : r < xi), kết quả sẽ là N=r*t với t>1. Lúc này, ta sẽ phải xét t trong khoảng [2,max(xi)] (chỉ xét đến max(xi) là vì khi t=max(xi) thì zi*t ≥ xi i => NN đã chia hết cho A, vậy không cần tìm t lớn hơn max(xi) nữa). Khi đó, với mỗi ước pi của A, ta xét số mũ của pi trong NN = p1 r*tp2r*t… pkr*t tr*t  có lớn hơn số mũ của pi trong A không. Nếu mọi số mũ pi trong NN đều lớn hơn hoặc bằng số mũ của pi trong A thì NN sẽ chia hết cho A (theo (*)) => N=r*t chính là giá trị nhỏ nhất để NN chia hết cho A.
Mã nguồn
#include <iostream>
#include <cmath>
using namespace std;

int demMu(int& iSo, int iUoc)
{
 int iDem = 0;
 while (iSo % iUoc == 0)
 {
  iSo /= iUoc;
  iDem++;
 }
 return iDem;
}

void main()
{
 int iA, iMaxMu = 1, iR = 1;
 cout << "Nhap gia tri cua A: ";
 cin >> iA;
 double dCanA = sqrt(iA * 1.0);
 int iABanDau = iA;

 for (int i = 2; i <= dCanA; i++)
  if (iA % i == 0)
  {
   int iMu = demMu(iA, i); 
   iR *= i;
   if (iMu > iMaxMu)
    iMaxMu = iMu;
  }

 if (iA > 1)
  iR *= iA;

 if (iMaxMu > iR)
  for (int k = 2; k <= iMaxMu; k++)
  {
   bool bEnd = true;
   iA = iABanDau;
   for (int i = 2; i <= dCanA; i++)
    if (iA % i == 0)
    {
     int iC = iR * k;
     int iMuA = demMu(iA, i);
     int iMuC = demMu(iC, i); 

     if (iMuC * iR * k < iMuA)
      bEnd = false;
    }
   if (bEnd) 
   {
    iR *= k;
    break;
   }
  }

 cout << "N nho nhat thoa N^N chia het cho A la: ";
 cout << iR << endl;
}