intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

Toán học và Tin học

Chia sẻ: Lê Công Vinh | Ngày: | Loại File: PDF | Số trang:392

90
lượt xem
7
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Tài liệu "Toán học và Tin học" trình bày về các bài toán ứng dụng trong tin học như bài toán xác định trọng tâm của một hình đa giác bất kỳ, bài toán về số Pi, bài toán mã đi tuần, phương pháp phân rã hình học để giải quyết bài toán trong tin học,... Để biết rõ hơn về nội dung chi tiết, mời các bạn cùng tham khảo.

Chủ đề:
Lưu

Nội dung Text: Toán học và Tin học

TOÁN HỌC VÀ TIN HỌC<br /> 1. Phương pháp phân rã hình học<br /> Trong các kỳ thi Tin học lập trình, tỉ lệ xuất hiện bài toán về hình học là rất cao. Mà<br /> đó lại thường là những bài mà học sinh vấp váp, vì một trong các lý do sau đây:<br /> - Thuật giải quá khó, không nghĩ ra.<br /> - Nghĩ ra được thuật giải, nhưng không cài đặt được vì quá phức tạp.<br /> - Thuật giải tốt, cài đặt xong, nhưng vẫn không ổn do những lỗi nho nhỏ tinh vi và<br /> khó tránh.<br /> Trong bài viết này, tôi xin được trình bày về một phương pháp có thể áp dụng cho<br /> một lớp rất lớn các bài toán tin có nội dung hình học: đó là phân rã bài toán ban đầu<br /> ra, đưa nó về một vài mô hình thật là đơn giản và cài đặt chỉ cần trình độ trung bình<br /> khá là ổn. Nội dung chính của phương pháp này mà tôi muốn nói cùng các bạn là:<br /> - Coi một góc là tập hợp vi phân các góc nhỏ liên tiếp. (1)<br /> - Coi một bao hình là một tập hợp vi phân các điểm liên tiếp. (2)<br /> Tất nhiên từ “vi phân” ở đây chỉ mang tính hình tượng, tức là một số vừa đủ lớn các<br /> góc vi phân, hay các điểm vi phân để cho (1) và (2) có thể coi như là đúng.<br /> Chúng ta sẽ đưa vấn đề đi cụ thể hơn sau khi phân tích một số bài tin sau đây:<br /> 1. Diện tích trong tam giác (Problem G - The 2004 ACM Asia Programming Contest<br /> - Beijing):<br /> <br /> Cho một tam giác và một vòng dây kín có độ dài biết trước. Hãy dùng vòng dây đó<br /> để khoanh một vùng kín nằm gọn trong tam giác sao cho diện tích phần thu được là<br /> lớn nhất.<br /> <br /> Input: Gồm nhiều bộ test, mỗi bộ gồm đúng bốn số dương được viết trên cùng một<br /> dọ̀ng. Ba số đầu tiên là độ dài ba cạnh của tam giác, số cuối cùng là chu vi vòng dây.<br /> Độ dài các cạnh của mảnh vườn không quá 100. Độ dài vòng dây không lớn hơn chu<br /> vi tam giác.<br /> Output: Gồm nhiều dọ̀ng, mỗi dọ̀ng ứng với một dọ̀ng trong input, chỉ ghi một số là<br /> diện tích lớn nhất có thể được, làm trọ̀n với đúng hai chữ số sau dấu thập phân<br /> Ví dụ:<br /> Input:<br /> 12.0000 23.0000 17.0000<br /> 40.0000<br /> 84.0000 35.0000 91.0000<br /> 210.0000<br /> 100.0000 100.0000 100.0000<br /> 181.3800<br /> Output:<br /> 89.35<br /> 1470.00<br /> 2618.00<br /> Có thể không khó khăn lắm để nhận ra được thuật giải của bài toán này như sau:<br /> Tìm O là giao ba đuờng phân giác của tam giác đó. Ta gọi R là bán kính đường tròn<br /> tâm O (bạn cứ coi là có R rồi). Phần diện tích tối ưu là phần mà vừa nằm trong<br /> đường tròn vừa nằm trong tam giác, đồng thời chu vi của phần diện tích đó đúng<br /> bằng L là chu vi vòng dây. Còn để tìm R thì ta chặt nhị phân.<br /> Chúng ta sẽ không bàn nhiều về thuật giải bài toán, cứ coi là bạn biết rồi đi. Vậy vấn<br /> đề là bạn sẽ cài đặt nó như thế nào? Quả thật rất khó để có thể hoàn thành bài này<br /> trong thời gian cho phép nếu như ta cứ cài đặt một cách thuần túy thông thường.<br /> Như vậy thì chẳng những mất thời gian mà hiệu quả đạt được còn là rất thấp.<br /> Sở dĩ bài này khó cài đặt là bởi vì ứng với mỗi R ta có rất nhiều trường hợp có thể<br /> xảy ra về vị trí tương đối của hình tròn (O) và tam giác ABC. Số điểm giao nhau có<br /> thể không có, có thể có một, có hai,..., hoặc có sáu giao điểm. Các giao điểm lại<br /> không xếp theo quy luật gì nên lúc thực sự tính toán lại nảy sinh nhiều vấn đề rất<br /> phức tạp, ví dụ như trên mỗi cạnh có mấy giao điểm? Điều này phải xác định rõ<br /> ràng, nếu không thì không thể tính được chu vi và diện tích của hình cần thiết. Tính<br /> sơ sơ ra số trường hợp cần xét cũng quá lớn và trong mỗi trường hợp cũng đủ rắc rối<br /> để cho ta có thể giải quyết bài này một cách nhanh gọn và chính xác (Tôi đã làm thử<br /> <br /> rồi). Vậy nếu đây là một bài thi quan trọng thì trong phòng thi liệu bạn có đủ bình<br /> tĩnh để làm một cách chính quy như trên? Tôi xin phát biểu phương án về cách phân<br /> rã bài toán này, để biến nó thành một bài toán đơn giản và rất dễ cài đặt, và từ đó<br /> tổng quát hóa lên một phương án tuyệt vời:<br /> Đầu tiên phải thấy được là cái khó chỉ là làm sao xác định rõ những giao điểm cần<br /> thiết. Gọi (T) là hình tạo bởi (0) và ABC ứng với R biết trước. Rõ ràng là (T) là một<br /> hình gồm có những phần đoạn thẳng (thuộc tam giác ABC) và những phần đường<br /> tròn (thuộc (O). Bây giờ ta không quan niệm (T) như vậy nữa, ta coi nó gần đúng là<br /> một đa giác (T') gồm rất nhiều điểm Mi, với 1 ≤ i ≤ P, với P bạn khai báo const ở<br /> đầu chương trình, P càng lớn càng tốt, nhưng không nên quá lớn vì chương trình sẽ<br /> chạy lâu hơn.<br /> Xác định các điểm Mi: Ta chia góc 3600 tại O ra làm P góc đều nhau. Ứng với góc<br /> thứ i đó ta vẽ một tia Oi, sau đó ta xác định xem tia Oi cắt hình tròn trước hay cắt<br /> tam giác trước. Michính là giao điểm gần O nhất trong hai giao điểm đó.<br /> Như vậy là thay vì phải tính toán với miền (T) vô cùng rắc rối, nếu ta coi nó như là<br /> một đa giác (T') gồm P đỉnh và xác định các điểm Mi dễ dàng như trên, thì công việc<br /> còn lại thật vô cùng đơn giản. Nhưng còn vấn đề sai số? Ta có thể khắc phục nó<br /> bằng một thủ thuật như sau:<br /> Đặt M0 = MP và MP+1 = M1. Xác định 6 điểm i mà góc giữa Mi-1, Mi, Mi+1 là<br /> lớn nhất. Đó chính là sáu giao điểm gần như thực sự của (T). Bây giờ ta tính toán<br /> trực tiếp trên (T) bằng cách dùng các công thức chính xác cho cung tròn và đoạn<br /> thẳng thì vấn đề sai số coi như không còn.<br /> <br /> Bạn thấy đó, cùng là một bài toán, nhưng nếu ta quan niệm nó khác đi một chút thì<br /> công việc sẽ được giảm tải đi rất nhiều lần. Không phải cứ cái gì tốt nhất về mặt lý<br /> thuyết cũng là tốt nhất với ta, nhất là trong các kỳ thi. Điều quan trọng là tính hiệu<br /> quả và thực tế của chương trình. Việc phân rã một hình (T) ra thành đa giác (T')<br /> cũng là điều thường gặp ở nhiều nơi, nhưng thủ thuật tách ra để rồi ghép lại thì quả<br /> là rất độc đáo. Thủ thuật này trong toán thường gặp khi phải tính tổng của một chuỗi<br /> số S, hay một chuỗi hàm f. Khi đó người ta hay vi phân vế trái, tính toán một hồi<br /> cho nó thật gọn rồi lại tích phân chính vế trái đó. Nếu như bạn để ý, về bản chất thì<br /> đó cũng là điều mà bài tin kia đã sử dụng, cho dù nó đã bị “tin hóa” đi bởi tham số<br /> P. Nhưng bạn cứ yên tâm, không có gì là tuyệt đối cả, nếu như P đủ lớn (khoảng vài<br /> nghìn) thì kết quả sẽ luôn ra tối ưu. Bài tin trên đã áp dụng cả (1) và (2) để giải<br /> quyết hiệu quả vấn đề. Có lẽ bạn vẫn chưa hình dung ra phương pháp này ra sao?<br /> Chúng ra hãy cùng bàn tiếp trong bài tiếp theo:<br /> 2. Chocolate<br /> Nhà máy sản xuất bánh kẹo Fishburg sản xuất ra một loại bánh chocolate hình đa<br /> giác lồi. Kiđy và Carlson mua một cái và họ muốn cắt nó ra làm hai phần bằng nhau<br /> với một nhát cắt có độ dài nhỏ nhất. Viết chương trình tìm độ dài nhỏ nhất để cắt<br /> miếng bánh sử dụng những gì bạn được cho biết về miếng bánh. Tổng số đỉnh N là<br /> một số nguyên (3 ≤ N ≤ 50). Tọa độ của các đỉnh là tập hợp các cặp số thực -100 ≤<br /> xi, yi≤100.<br /> Input: Dòng đầu của input file gồm số N - số lượng đỉnh của đa giác. N dòng sau<br /> gồm toạ độ của các đỉnh liên tiếp nhau của đa giác.<br /> Output: gồm độ dài nhỏ nhất của đường cắt chính xác đến 0,0001.<br /> Ví dụ:<br /> Input:<br /> 4<br /> 00<br /> 03<br /> 43<br /> 40<br /> Output:<br /> 3<br /> Thuật giải tốt của bài này theo tôi là không phù hợp để bàn ra ở đây vì cái lõi toán<br /> của nó nhiều quá. Nói chung để mà vừa nghĩ thuật giải tốt hẳn và cài đặt xong nó<br /> <br /> chắc cũng phải vất vả nhiều lắm mà cũng chẳng biết là liệu mình có kiểm soát được<br /> không nữa. Vậy chúng ta cùng bàn cách phân rã bài này ra cho nó đơn giản đi nhé.<br /> Cách đơn giản nhất ai cũng có thể nghĩ ra là coi như đa giác này là một tập hợp các<br /> điểm rời rạc, sau đó ta lấy hai trong số những điểm đó, rồi kiểm tra xem đoạn thẳng<br /> nối hai điểm này có chia đôi được đa giác hay không, nếu như được rồi thì cập nhật<br /> kết quả thôi. Cải tiến của cách này là chỉ chọn một điểm thôi, điểm còn lại thì chặt<br /> nhị phân. Cách này về tư tưởng phân rã thì là tốt nhưng trên thực tế không phải là<br /> không có vấn đề. Điều kiện các tọa độ của đa giác có trị tuyệt đối không quá 100<br /> cho nên sẽ vẫn có những test mà chu vi của nó sẽ khá là lớn (có thể lên tới hàng<br /> vạn). Mà theo như cách phân rã này thì độ sai số sẽ tỉ lệ theo chu vi của đa giác. Nếu<br /> chia đa giác thành P điểm, với độ phức tạp của cách này vượt quá Plog(P), thì rõ<br /> ràng muốn chạy nhanh được thì P không thể tới hàng vạn, cho nên khả năng chính<br /> xác tới nhiều chữ số sau dấu thập phân khi chu vi của đa giác quá lớn là điều không<br /> tưởng. Vậy (2) không dùng được ở đây.<br /> Cách thứ hai có thể khắc phục nhược điểm trên, là ta phân rã các góc ra thành vô số<br /> các góc nhỏ vi phân. Giả sử số góc là P, thì một góc sẽ có giá trị là dP = 3600/P.<br /> Chắc hẳn đọc đề bài lần đầu ai cũng tưởng tượng là đa giác thì đứng yên, còn đường<br /> thẳng chia đôi đa giác sẽ xiên xiên. Ta hãy tưởng tượng ngược lại một chút như sau:<br /> Đường thẳng chia đôi đa giác thì luôn nằm ngang, có thể tịnh tiến lên xuống, còn đa<br /> giác thì có thể xoay. Về bản chất thì vẫn không có gì thay đổi, nhưng nó sẽ giúp ích<br /> nhiều cho ta. Tóm lại thuật giải sẽ như sau:<br /> - Xoay đa giác đi một góc dP.<br /> - Chặt nhị phân để tịnh tiến đường thẳng nằm ngang sao cho nó chia đôi đa giác kia.<br /> Nếu không chia vừa thì bằng cách chặt nhị phân ta có thể tịnh tiến đường thẳng này<br /> lên xuống đến bao giờ bằng nhau thì thôi.<br /> - Sau khi đã chia đôi đa giác, cập nhật lại độ dài tốt nhất của nhát cắt. Sau khi xoay<br /> đi P lần, mỗi lần một góc dP thì đa giác sẽ quay về đúng vị trí ban đầu. Nếu như có<br /> bạn nào chưa biết công thức xoay hình, tôi xin được viết luôn ra đây:<br /> xmới = xcũ.cos(alpha) – ycũ.sin(alpha).<br /> ymới = xcũ.sin(alpha) + y cũ.cos(alpha).<br /> Trong đó alpha là góc quay.<br /> Tất nhiên P càng lớn thì càng tốt. Đối với bài này tôi để P = 35000/N và chạy đúng<br /> hết tất cả các test. Đó chính là kết quả của việc áp dụng tính phân rã thứ (1).<br /> <br />
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2