diff --git a/MaxRect.java b/MaxRect.java new file mode 100644 index 0000000..c619ab9 --- /dev/null +++ b/MaxRect.java @@ -0,0 +1,41 @@ +import acm.program.ConsoleProgram; + +public class MaxRect extends ConsoleProgram { + + private int maxRect(int[][] arr) { + int max = 0; + for (int r = 0; r < arr.length; r++) { + for (int c = 0; c < arr[r].length; c++) { + + if (arr[r][c] == 1) { + for (int i = r; i < arr.length; i++) { + for (int j = c; j < arr[i].length; j++) { + + if (arr[i][j] == 1) { + if (allOnes(arr, r, c, i, j)) { + if ((i - r + 1) * (j - c + 1) > max) { + max = (i - r + 1) * (j - c + 1); + } + } + } + + } + } + } + + } + } + return max; + } + + private boolean allOnes(int[][] arr, int r, int c, int i, int j) { + for (int k = r; k <= i; k++) { + for (int p = c; p <= j; p++) { + if (arr[k][p] != 1) { + return false; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/MaxRect.md b/MaxRect.md new file mode 100644 index 0000000..56dae61 --- /dev/null +++ b/MaxRect.md @@ -0,0 +1,117 @@ +# MaxRect + +პრობლემა: +``` + გადმოგეცემათ nxm-ზე მატრიცა რომელშიც მხოლოდ 0-ები და 1-ები წერია. მეთოდმა +უნდა დააბრუნოს ამ მატრიცის ყველაზე დიდი ქვემართკუთხედის +ზომა(ელემენტების რაოდენობა) რომელიც მხოლოდ 1-ებისგან შედგება. +მაგალითად: + + 01100100 + 01111100 + 00111100 + 00111100 + + ამ მატრიცაში ყველაზე დიდი შიდა მართკუთხედი, რომელიც სულ ერთიანებისგან +შედგება არის 12 ზომის: + + 01 1001 00 + 01*1111*00 + 00*1111*00 + 00*1111*00 + + შესაბამისად ამ მატრიცაზე მეთოდმა უნდა დააბრუნოს 12. ჩათვალეთ რომ +გადმოცემულ მატრიცაში ერთი უჯრა მაინც იქნება რომელშიც წერია 1. + +``` + +## პროლბლემის გააზრება: + +* ჩვენ გადმოცემულ მატრიცაში უნდა ვიპოვოთ ისეთი მართკუთხედი, რომელიც შედგენილი იქნება მხოლოდ ერთიანებისაგან, მაგ: +``` + 111 1 11 + 111 1 11 +``` + +* ამ ამოცანაში მთავარია მოვიფიქროთ, თუ როგორ ვიპოვოთ ასეთი მართკუთხედები, კოდის დაწერა კი არც ისე რთულია. + +## პრობლემის გადაჭრის გზა: + +* მე გთავაზობთ შემდეგს: + +* გადავუყვეთ მატრიცის თითოეულ ელემენტს და თითოეულისათვის გავაკეთოთ შემდეგი რამ: + +* დავიმახსოვროთ მოცემული წერტილი. შემდეგ ამ წერტილიდან მარჯვნივ და ქვემოთ გადავუყვეთ სხვა წერტილებს. ალბათ გაინტერესებთ, თუ რას წარმოადგენენ ეს სხვა წერტილები?! ეს სხვა წერტილები არიან დამახსოვრებული წერტილის მოპირდაპირე წერტილები მართკუთხედში. იხილეთ სურათი: checkForAllPoints.png, რომელშიც განხილულია თუ როგორ ვიქცევით პირველი წერტილისათვის მატრიცაში. ანალოგიური მიდგომაა სხვა წერტილებზეც. + +* დამახსოვრებული წერტილი და "ის რაღაც სხვა წერტილი" რომ შევაერთოთ მართკუთხედში მივიღებთ დიაგონალს. ეს ყველაფერი რომ უკეთ წარმოიდგინოთ, ნახეთ სურათი: diagonalPoints.png. + +* შემდეგ უნდა შევამოწმოთ არის თუ არა ამ მოცემულ სამკუთხედში სულ ერთიანები. თუ პასუხი არის `true` უნდა შევამოწმოთ ამ მართკუთხედის ფართობი არის თუ არა მეტი მანამდე შემოწმებულ მართკუთხედების ფართობებზე. თუ პასუხი არის `false`, არაფერს ვაკეთებთ და გადავდივართ შემდეგ წერტილზე. + +## კოდის რეალიზაცია: + +* პირბელ რიგში, შევქმნათ მეთოდი რომელიც გვიბრუნებს მაქსიმალური ფართობის მქონე მართკუთხედის ფართობს, `private int maxRect(int[][] arr)`, რომელსაც გადავცემთ მატრიცას. + +* მივყვეთ "პრობლემის გადაჭრის გზაში" მოცემულ ნაბიჯებს და დავწეროთ შესაბამისი კოდი. + +* გადავუყვეთ მატრიცის თითოეულ ელემენტს: +```java + for (int r = 0; r < arr.length; r++) { + for (int c = 0; c < arr[r].length; c++) { +``` +სადაც r არის შესაბამისი სტრიქონის ნომერი და c არის შესაბამისი სვეტის ნომერი. + +* დავიმახსოვროთ მოცემული წერტილი: +```java + if (arr[r][c] == 1) { +``` + თუ მოცემული წერტილი 1 ის ტოლი არაა ჩვენ არ გვაინტერესებს ეს წერტილი და გადავდივართ შემდეგ წერტილზე, რადგან რა დიდი მართკუთხედის წერტილიც არ უნდა იყოს ეს წერტილი, ამ მართკუთხედში ყველა ელემენტი 1 ის ტოლი არ გამოვა. + +* ვიპოვოთ მეორე წერტილი, რომელიც ამჟამად მყოფი ელემენტის ან მარჯვნივ დგას ან ქვემოთ: +```java + for (int i = r; i < arr.length; i++) { + for (int j = c; j < arr[i].length; j++) { +``` + შევამოწმოთ არის თუ არა ეს მეორე წერტილიც 1 ის ტოლი. თუ არაა, მაშინ ჩვენ ამ ორი წერტილით მოჭიმული მართკუთხედიც არ გვაინტერესებს ზემოთხსენებული მიზეზის გამო. + +```java + if (arr[i][j] == 1) { +``` +სადაც i და j წარმოადგენენ მეორე წერტილისთვის სტრიქონის ნომერს და სვეტის ნომერს. + +* შევამოწმოთ არის თუ არა ამ ორი წერტილით მოჭიმულ მართკუთხედში ყველა ერთიანი. +```java + if (allOnes(arr, r, c, i, j)) { +``` + მეთოდი, `allOnes(arr, r, c, i, j)`, გადაუყვება ამ ორ წერტილით მოჭიმულ მართკუთხედში ყველა ელემენტს და თუ იპოვის 0 ს აბრუნებს `false`, ხოლო თუ 0 იანი არ გვხვდება, აბრუნებს `true` ს. კოდი საკმაოდ მარტივია: + +```java + for (int k = r; k <= i; k++) { + for (int p = c; p <= j; p++) { + if (arr[k][p] != 1) { + return false; + } + } + } + return true; +``` + გადაუყვება სტრიქონებს r დან i მდე და სვეტებს c დან j მდე. r <= i, c <= j. + +* ახლა უნდა შევამოწმოთ არის თუ არა ეს მართკუთხედი მაქსიმალური ფართობის მქონე. +```java + if ((i - r + 1) * (j - c + 1) > max) { + max = (i - r + 1) * (j - c + 1); + } +``` + max არის რაღაც ცვლადი, რომელშიც ვინახავთ მაქსიმალური ფართობის მქონე მართკუთხედის ფართობს. + + იმის მიხვედრას თუ როგორ ვიგებთ გვერდებს, ეს საკმაოდ მარტივია. `i - r` და `j - c`. თუმცა გაგიკვირდებათ, თუ რატომ ვუმატებთ თითოეულ გვერდს კიდევ ერთს. რომ წარმოვიდგინოთ მხოლოდ წერტილი და კოდში დაგვეწერა `(i - r) * (j - c)`, პასუხს ამ შემთხვევისათვის მივიღებდით ნულს, როდესაც რეალურად ის ერთის ტოლია. ან რო გვქონოდა წერტილების გვერდიგვერდ, მაშინ პასუხი გამოგვივიდოდა 0 და აშ. ამიტომ ამ ზემოხსენებულ მონაცემებს დამატებით უნდა დავუმატოთ კიდევ ერთი. + +### შესაძლო ხარვეზები: + +* ერთი ხარვეზი უკვე მოგახსენეთ "კოდის რეალიზაციაში", როდესაც ვისაუბრეთ, თუ რატომ ჭირდებოდა ზემოხსენებულ მონაცემებს ერთის დამატება. + +* მეორე ხარვეზი შესაძლოა ყოფილიყო შემდეგი: `(r - i + 1)`, რაც არასწორია რადგან r <= i და ზოგ შემთხვევაში ეს უარყოფით რიცხვს მოგვცემდა, რაც არასწორია. ამის გამოსწორება შეიძლება თუ დავწერთ `(i - r + 1)` ან ავიღებთ სხვაობის მოდულს. ანალოგიურად ვიქცევით სვეტებზეც. + +* ზოგმა შეიძლება ჩათვალოს, რომ i > r, რაც არასწორია, რადგან ამით ჩვენ ვუარყოფთ ისეთ მაგალითებს, როგორებიცაა: 1x1, 1x2, 1x5 და აშ. ანალოგიურად სვეტებზეც. + +* შემოწმების დროსაც, როდესაც ვამოწმებთ არის თუ არა მოცემულ მართკუთხედში ყველა ერთიანი, ჩვენ უნდა გავითვალისწინოთ ის წერტილებიც, რომლებიც ამ მართკუთხედს ჭიმავენ, რადგან წინააღმდეგ შემთხვევაში ჩვენ ჩავთვლით, რომ ამ წერტილების ზევით, ქვემოთ, და გვერდზე ერთიანები წერია, რაც არასწორია, რადგან ჩვენ მხოლოდ ვიცით, რომ ეს წერტილები არიან მხოლოდ და მხოლოდ ერთიანების ტოლი. სურათი, რომ უკეთ წარმოიდგინოთ, ნახეთ სურათი: errorInCheckingElements.png. diff --git a/checkForAllPoints.png b/checkForAllPoints.png new file mode 100644 index 0000000..75b11ef Binary files /dev/null and b/checkForAllPoints.png differ diff --git a/diagonalPoints.png b/diagonalPoints.png new file mode 100644 index 0000000..1815049 Binary files /dev/null and b/diagonalPoints.png differ diff --git a/errorInCheckingElements.png b/errorInCheckingElements.png new file mode 100644 index 0000000..75b11ef Binary files /dev/null and b/errorInCheckingElements.png differ