Sáng tạo trong thuật toán và lập trình với ngôn ngữ Pascal và C# - Tập 2 - Chương 1: Các bài toán về đoạn thẳng
Phương pháp: tham.
1. Sắp các đoạn tăng theo đầu phải b.
2. Khởi trị: Lấy đoạn 1, đặt r = b
1 là đầu phải của đoạn này
3. Với mỗi đoạn j := 2.N tiếp theo xét:
Nếu đầu trái của đoạn j, a
j
> r thì lấy đoạn j đưa vào kết quả
và chỉnh r là đầu phải của đoạn j, r := b
j
.
Độ phức tạp: cỡ NlogN chi phí cho quick sort.
static public void Ghi() { File.WriteAllText(gn,dt.ToString()); } static public void XemKetQua(): tự viết static public void XuLi(){ dt = 0; // tong dien tich int[] s = new int[m]; // diem dau cac bang int [] e = new int [m]; // diem cuoi cac bang for (int i = 0; i < m; ++i) s[i] = e[i] = int.MinValue; // Duyet cac HCN for (int i = 0; i < n; ++i) { // xu li HCN i int sj = BinSearch(c[i].y1); int ej = BinSearch(c[i].y2); for (int j = sj; j < ej; ++j){ // xet bang j if (c[i].x1 <= e[j]) e[j] = Max(e[j], c[i].x2); else { dt += (e[j] - s[j])*(y[j+1]-y[j]); s[j] = c[i].x1; e[j] = c[i].x2; } } } // Tong hop ket qua int m1 = m - 1; for (int j = 0; j < m1; ++j) dt += (e[j] - s[j])*(y[j+1]-y[j]); } static public int Max(int a, int b): tự viết static public void Doc() { int[] v = Array.ConvertAll(((File.ReadAllText(fn))).Split( new chae[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries), new Converter(int.Parse)); int j = 0; n = v[j]; c = new HCN[n]; int dx, dy, bx, by, t; m = 0; y = new int[2*n]; for (int i = 0; i < n; ++i, j += 4) { dx = v[j + 1]; dy = v[j + 2]; bx = v[j + 3]; by = v[j + 4]; if (dx > bx) { t = dx; dx = bx; bx = t; } if (dy > by) { t = dy; dy = by; by = t; } 46 c[i] = new HCN(dx, dy, bx, by); Insert(dy); Insert(by); } } // Tim nhi phan gia tri v trong y[0..m-1] static public int BinSearch(int v) { int left = 0, right = m-1, midle; while (left < right) { midle = (left + right)/2; if (y[midle] < v) left = midle + 1; else right = midle; } return left; } // Xen toa do v vao danh sach cac lan y static public void Insert(int v) { if (m == 0) { y[m++] = v; return; } int i = BinSearch(v); if (y[i] == v) return; if (y[i] < v) { y[m++] = v; return; } Array.Copy(y, i, y, i + 1, m - i); y[i] = v; ++m; } // Sap cac HCN tang theo x1 static public void QSortByx1(int s, int e) { int i = s, j = e, m = c[(i + j) / 2].x1; HCN t; while (i <= j) { while (c[i].x1 < m) ++i; while (c[j].x1 > m) --j; if (i <= j) { t = c[i]; c[i] = c[j]; c[j] = t; ++i; --j; } } if (s < j) QSortByx1(s, j); if (i < e) QSortByx1(i, e); } } // Hcn public struct HCN { public int x1,y1,x2,y2; public HCN(int dx, int dy, int bx, int by) { x1 = dx; y1 = dy; x2 = bx; y2 = by; } } } // SangTao2 Bài 1.16 Các tam giác vuông cân ACM Trên mặt phẳng tọa độ cho N tam giác vuông cân, hai cạnh góc vuông song song với hai trục tọa độ, cạnh huyền nằm ở bên phải tam giác. Cụ thể là nếu kí hiệu tam giác là ABC thì ta qui định đỉnh A là đỉnh góc vuông, cạnh góc vuông AB song song với trục hoành ox, cạnh góc vuông AC song song với trục tung oy, AB = AC = d. Mỗi tam giác được mô tả bằng bộ ba số nguyên x, y, d trong đó (x,y) là tọa độ nguyên của đỉnh A, d là chiều dài cạnh góc vuông. TAMGIAC.INP TAMGIAC.OUT 47 Yêu cầu: Tính diện tích do các tam giác phủ trên mặt phẳng tọa độ. Dữ liệu vào: text file TAMGIAC.INP Dòng đầu tiên: số tự nhiên N trong khoảng 2 .. 1000. N dòng tiếp theo: mỗi dòng 3 số x y d cách nhau qua dấu cách, x và y biến thiên trong khoảng 1000..1000, d trong khoảng 1..1000. Dữ liệu ra: text file TAMGIAC.OUT chứa một số thực duy nhất S là diện tích bị các tam giác phủ trên mặt phẳng tọa độ. Thuật toán Tương tự như bài Các Hình chữ nhật. Với mỗi tam giác (x, y, d) ta tạo ra hai đường song song với trục hoành và cắt trục tung tại các điểm y và y+d, cụ thể là một đường chứa cạnh đáy và một đường đi qua đỉnh của tam giác. Các đường thẳng này sẽ tạo ra các băng. Với mỗi tam giác (TG) ta cũng xét tương tự như HCN, nghĩa là xét các băng chứa trong TG đó. Biến diện tích dt được khai báo kiểu float vì các hình trong băng j sẽ là hình thang có đáy lớn là e[j]s[j], đáy nhỏ bằng đáy lớn – h, h là chiều cao: h = y[j+1]y[j] = độ rộng của băng. Khi chuyển từ băng j lên băng j+1 ta phải chỉnh lại đầu phải x2 của cạnh đáy TG thành x2 – h vì TG lúc này sẽ ngắn lại. Khi tính phần giao nhau ta còn phải trừ đi diện tích của TG nằm ngoài phần giao đó. Hình vẽ cho ta thấy khi xét tam giác XYV và băng giới hạn trong 2 đường thẳng TM và SE, thì làn (S, E) sẽ được mở rộng thành làn (S, V). Diện tích trước đó của làn SE chính là diện tích hình thang vuông TMES, nay làn (S,V) có diện tích của hình thang vuông TRVS. Như vậy ta đã tính dôi ra phần diện tích tam giác MPQ. Dễ dàng xác định được diện tích z của tam giác vuông cân này: Đặt k = MP = PQ, ta có z = k2/2.Ta xác định k như sau. k = MP = TP TM = SXTM = x(e[j]h), trong đó h là chiều rộng của băng j đang xét, h = y[j+1]y[j], e[j] là điểm cuối của làn đang xét, x là hoành độ của đỉnh góc vuông trong tam giác XYV đang xét. Độ phức tạp: N2. (* Pascal *) (********************************************** Cac tam giac vuong can *********************************************) program TamGiacVuongCan; uses crt; const mn = 2001; bl = #32; nl = #13#10; 5 6 0 3 1 0 3 2 1 3 4 1 2 4 5 2 16.50 y C A B o x T M S Y X V E R P Q 48 fn = 'TamGiac.inp'; gn = 'TamGiac.out'; type TG = record x,y: integer; d: integer; end; mtg1 = array[0..mn] of TG; mi1 = array[0..mn] of integer; mr1 = array[0..mn] of real; var n,m: integer; { n - so tam giac } y: mi1; { m - so diem y, max(m) = 2n } t: mtg1; f,g: text; dt: real; // tong dien tich (*-------------------------------------------- To chuc du lieu cho Bang i s[i], e[i] - can trai va phai cua Bang ----------------------------------------------*) s, e: mi1; function Max(a,b: integer): tự viết (*----------------------------- Xen them v vao day da sap tang y[1..m] ------------------------------*) procedure Insert(v: integer); tự viết procedure Doc; var i: integer; begin assign(f,fn); reset(f); readln(f,n); m := 0; for i := 1 to n do begin readln(f,t[i].x,t[i].y,t[i].d); Insert(t[i].y); Insert(t[i].y + t[i].d); end; close(f); end; { Sap cac TG tang theo x } procedure SortByX(d,c: integer); tự viết { Tim nhi phan v trong y[1..m] } function BinSearch(v: integer): integer; tự viết (*--------------------------------------- Xet hinh Tam giac h: tinh cac o hinh h phu tren cac Bang --------------------------------------*) procedure Hinh(x1,y1,d: integer); var i,y2,x2,h,k: integer; begin { Tim xuat hien cua toa do y1 trong cac lan } i := BinSearch(y1); x2 := x1 + d; y2 := y1 + d; while (y[i] < y2) do begin h := y[i + 1] - y[i]; if (x1 <= e[i]) then begin k := x1 - (e[i] - h); e[i] := Max(e[i], x2); 49 if (k > 0) then dt := dt - (real(k * k) / 2); end else begin if (e[i] > s[i]) then dt := dt + h * (2 * (e[i] - s[i]) - h) / 2; s[i] := x1; e[i] := x2; end; i := i + 1; x2 := x2 - h; end; end; procedure XuLi; var i, h: integer; begin for i := 1 to m do begin s[i] := -maxint; e[i] := s[i]; end; dt := 0.0; { Duyet cac TG } for i := 1 to n do Hinh(t[i].x,t[i].y,t[i].d); { Tong hop ket qua } for i := 1 to m-1 do begin h := y[i + 1] - y[i]; if (e[i] > s[i]) then dt := dt + h * (2 * (e[i] - s[i]) - h) / 2; end; end; procedure Ghi; begin assign(g,gn); rewrite(g); writeln(g,dt:0:2); close(g) end; BEGIN Doc; SortByX(1,n); XuLi; Ghi; END. // C# using System; using System.IO; using System.Collections; namespace SangTao2 { class TamGiac { const string fn = "TamGiac.inp"; const string gn = "TamGiac.out"; static public int n, m; // n - so luong HCN; m - so bang static public TG[] c; static public float dt; // tong dien tich static public int[] y; static void Main(string[] args){ Doc(); QSortByx1(0, n - 1); XuLi(); Ghi(); XemKetQua(); Console.WriteLine("\n Fini "); Console.ReadLine(); } static public void Ghi(): tự viết static public void XemKetQua(): tự viết static public void XuLi() { dt = 0F; 50 int[] s = new int[m]; int[] e = new int[m]; for (int i = 0; i < m; ++i) s[i] = e[i] = int.MinValue; // Duyet cac TG c[i] for (int i = 0; i < n; ++i) { int x2 = c[i].x1+c[i].d; // dau phai cua canh day int sj = BinSearch(c[i].y1); int ej = BinSearch(c[i].y1 + c[i].d); for (int j = sj; j < ej; ++j) { // xet bang j int h = y[j + 1] - y[j]; // do rong cua bang j if (c[i].x1 <= e[j]) { int k = c[i].x1 - (e[j] - h); if (k > 0) dt -= (float)(k * k) / 2; e[j] = Max(e[j], x2); } else { if (e[j] > s[j]) dt += (float)(2*(e[j]-s[j])-h)*h/2; s[j] = c[i].x1; e[j] = x2; } x2 -= h; } // xong bang j } // xong TG i // Tong hop ket qua int m1 = m - 1; for (int j = 0; j < m1; ++j) { int h = y[j+1]-y[j]; // do rong cua bang if (e[j] > s[j]) dt += (float)(2*(e[j]-s[j])-h)* h/2; } static public int Max(int a, int b): tự viết static public void Doc() { int[] v = Array.ConvertAll(((File.ReadAllText(fn))).Split( new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries), new Converter(int.Parse)); int j = 0; n = v[j]; c = new TG[n]; m = 0; y = new int[2 * n]; for (int i = 0; i < n; ++i, j += 3) { Insert(v[j + 2]); Insert(v[j + 2] + v[j + 3]); c[i] = new TG(v[j + 1], v[j + 2], v[j + 3]); } } // Tim nhi phan gia tri v trong y[0..m-1] static public int BinSearch(int v): tự viết // Xen toa do v vao danh sach cac lan y static public void Insert(int v): tự viết // Sap cac TG tang theo x1 static public void QSortByx1(int s, int e): tự viết } // TamGiac public struct TG { public int x1, y1, d; 51 public TG(int dx, int dy, int dd) { x1 = dx; y1 = dy; d = dd; } } } // SangTao2
File đính kèm:
- Sáng tạo trong thuật toán và lập trình với ngôn ngữ Pascal và C# - Tập 2 - Chương 1_Các bài toán về đoạn thẳng.pdf