Adott egy téglalap alakú papír méretei a x b . A feladat az, hogy az egész papírt a minimális száma négyzet darabok. Bármilyen méretű négyzet alakú darabot választhatunk, de ezeket vágni kell anélkül, hogy átfedne, vagy extra helyet hagyna .
Példák:
Bemenet: a = 5 b = 8
5 db 5 x 8 méretű papírból kivágott négyzet
Kimenet: 5
Magyarázat: A papírt 5 négyzetre vághatjuk: 1 négyzet 5x5 1 négyzet 3x3 1 négyzet 2x2 és 2 négyzet 1x1 méretű.Bemenet: a = 13 b = 11
6 négyzet 13x11 méretű papírból vágva
Kimenet: 6
Magyarázat: A papírt 6 négyzetre vághatjuk: 1 négyzet 7x7 1 négyzet 6x6 1 négyzet 5x5 2 négyzet 4x4 és 1 négyzet 1x1 méretű.diszkrét matematikai tagadásBemenet: a = 6 b = 7
5 négyzet 6x7 méretű papírból vágva
Kimenet: 5
Magyarázat: A papírt 5 négyzetre vághatjuk: 1 négyzet 4x4 2 négyzet 3x3 és 2 négyzet 3x3 méretű.
Tartalomjegyzék
- [Helytelen megközelítés 1] Mohó technika használata
- [2. helytelen megközelítés] Dinamikus programozás használata
- [Helyes megközelítés] DFS és dinamikus programozás használata
[Helytelen megközelítés 1] Mohó technika használata
Első pillantásra úgy tűnhet, hogy a probléma könnyen megoldható úgy, hogy először a lehető legnagyobb négyzetet vágjuk ki a papírból, majd a maradék papírból vágjuk ki a legnagyobb négyzetet, és így tovább, amíg az egész papírt le nem vágjuk. De ez a megoldás helytelen.
Miért nem működik a Greedy Approach?
Vegyünk egy méretű papírt 6x7 majd ha mohón próbáljuk vágni a papírt, akkor azt kapjuk 7 négyzetek: 1 négyzet méretű 6x6 és 6 négyzet méretű 1x1 míg a helyes megoldás: 5. Ezért a mohó megközelítés nem fog működni.
[2. helytelen megközelítés] Dinamikus programozás használata
Dinamikus programozás függőleges vagy vízszintes vágásokkal: Egy másik megoldás, amely helyesnek tűnhet, a használata Dinamikus programozás . Fenntarthatunk egy dp[][] táblát úgy, hogy dp[i][j] = a méretű papírból kivágható négyzetek minimális száma i x j . Aztán méretű papírra axb
- Megpróbálhatjuk minden sor mentén levágni: dp[i][j] = min(dp[i][j] 1 + dp[i - k][j] + dp[k][j]) ahol k az [1 i - 1] tartományban lehet.
- Megpróbálhatjuk minden oszlop mentén vágni: dp[i][j] = min(dp[i][j] 1 + dp[i][j - k] + dp[i][k]) ahol k az [1 j - 1] tartományban lehet.
Végül a minimális vágás lesz a válasz. De ez a megoldás is helytelen.
Miért nem működik a függőleges vagy vízszintes vágás a dinamikus programozási módszerrel?
Ez nem fog működni, mert feltételezzük, hogy a függőleges vagy vízszintes vágás mindig két részre osztja a téglalapot. Vegyünk egy méretű papírt 13x11 akkor ha DP megközelítéssel próbáljuk kivágni a papírt, 8 négyzetet kapunk, de a helyes válasz (a példákban látható) 6. Ezért a dinamikus programozás nem fog működni.
[Helyes megközelítés] DFS és dinamikus programozás használata
C++A ötlet az egész papírt le kell vágni DFS be alulról felfelé módon. Minden lépésben keresse meg a papír bal alsó sarkát, és próbáljon meg abból a sarokból kivágni minden lehetséges méretű négyzetet. Miután újra kivágott egy négyzetet, keresse meg a maradék papír bal alsó sarkát, hogy minden lehetséges méretű négyzetet kivághasson és így tovább. De ha minden lehetséges papírméretet a bal alsó sarokból próbálnánk kivágni, akkor az eléggé hatástalan lenne. Használatával tudjuk optimalizálni Dinamikus programozás hogy minden lehetséges papírmérethez minimális vágást tároljon.
Bármely papírméret egyedi azonosításához fenntarthatunk egy remSq[] tömböt úgy, hogy a remSq[i] a papír i-edik oszlopában tárolja a fennmaradó 1x1 méretű négyzetek számát. Tehát egy 6x7 remSq [] méretű papírra = {6 6 6 6 6 6 6}. Szintén a bal alsó sarok megkereséséhez megtaláljuk az első indexet, amely a maximálisan megmaradt négyzeteket tartalmazza. Így kivonatolhatjuk a remSq[] tömb értékét, hogy egyedi kulcsot találjunk a remSq[] tömb összes lehetséges értékéhez.
// C++ Program to find minimum number of squares to cut // from a paper of size axb #include using namespace std; // function to get the hash key for remSq array int getKey(vector<int> &remSq int b) { int base = 1; int key = 0; for (int i = 0; i < b; i++) { key += (remSq[i] * base); base = base * (b + 1); } return key; } // Recursive function to find the minimum number of square cuts // for a given remSq array int minCutUtil(vector<int> &remSq int a int b map<int int> &memo) { // pointers to mark the start and end of range // with maximum remaining squares int start end; // Check if we have previously calculated the answer // for the same state int key = getKey(remSq b); if (memo.find(key) != memo.end()) return memo[key]; int maxRemSq = 0; // Find the starting point of min height for (int i = 0; i < b; i++) { if (remSq[i] > maxRemSq) { maxRemSq = remSq[i]; start = i; } } // If max remaining squares = 0 then we have already // cut the entire paper if (maxRemSq == 0) return 0; end = start; vector<int> newRemSq = remSq; int ans = INT_MAX; // Find the ending point of min height while (end < b) { // length of edge of square from start till current end int squareEdge = end - start + 1; // If the current column does not have maximum remaining // squares or if it's impossible to cut a square of // size squareEdge then break out of the loop if (newRemSq[end] != maxRemSq || newRemSq[end] - squareEdge < 0) break; // If we can cut a square of size squareEdge // update the remainingSquares for (int i = start; i <= end; i++) newRemSq[i] = maxRemSq - squareEdge; // Find the solution for new remainingSquares ans = min(ans 1 + minCutUtil(newRemSq a b memo)); end += 1; } return memo[key] = ans; } // Function to find the minimum number of squares we can cut // using paper of size a X b int minCut(int a int b) { // if the given rectangle is a square if (a == b) return 1; // Initialize remaining squares = a for all the b columns vector<int> remSq(b a); map<int int> memo; return minCutUtil(remSq a b memo); } int main() { // Sample Input int a = 13 b = 11; // Function call to get minimum number // of squares for axb cout << minCut(a b); return 0; }
Java // Java Program to find minimum number of squares to cut // from a paper of size axb import java.util.*; class GfG { // function to get the hash key for remSq array static int getKey(int[] remSq int b) { int base = 1; int key = 0; for (int i = 0; i < b; i++) { key += (remSq[i] * base); base = base * (b + 1); } return key; } // Recursive function to find the minimum number of square cuts // for a given remSq array static int minCutUtil(int[] remSq int a int b Map<Integer Integer> memo) { // pointers to mark the start and end of range // with maximum remaining squares int start = 0 end; // Check if we have previously calculated the answer // for the same state int key = getKey(remSq b); if (memo.containsKey(key)) return memo.get(key); int maxRemSq = 0; // Find the starting point of min height for (int i = 0; i < b; i++) { if (remSq[i] > maxRemSq) { maxRemSq = remSq[i]; start = i; } } // If max remaining squares = 0 then we have already // cut the entire paper if (maxRemSq == 0) return 0; end = start; int[] newRemSq = Arrays.copyOf(remSq b); int ans = Integer.MAX_VALUE; // Find the ending point of min height while (end < b) { // length of edge of square from start till current end int squareEdge = end - start + 1; // If the current column does not have maximum remaining // squares or if it's impossible to cut a square of // size squareEdge then break out of the loop if (newRemSq[end] != maxRemSq || newRemSq[end] - squareEdge < 0) break; // If we can cut a square of size squareEdge // update the remainingSquares for (int i = start; i <= end; i++) newRemSq[i] = maxRemSq - squareEdge; // Find the solution for new remainingSquares ans = Math.min(ans 1 + minCutUtil(newRemSq a b memo)); end += 1; } memo.put(key ans); return ans; } // Function to find the minimum number of squares we can cut // using paper of size a X b static int minCut(int a int b) { // if the given rectangle is a square if (a == b) return 1; // Initialize remaining squares = a for all the b columns int[] remSq = new int[b]; Arrays.fill(remSq a); Map<Integer Integer> memo = new HashMap<>(); return minCutUtil(remSq a b memo); } public static void main(String[] args) { // Sample Input int a = 13 b = 11; // Function call to get minimum number // of squares for axb System.out.println(minCut(a b)); } }
Python # Python Program to find minimum number of squares to cut # from a paper of size axb # function to get the hash key for remSq array def getKey(remSq b): base = 1 key = 0 for i in range(b): key += remSq[i] * base base = base * (b + 1) return key # Recursive function to find the minimum number of square cuts # for a given remSq array def minCutUtil(remSq a b memo): # pointers to mark the start and end of range # with maximum remaining squares start = 0 # Check if we have previously calculated the answer # for the same state key = getKey(remSq b) if key in memo: return memo[key] maxRemSq = 0 # Find the starting point of min height for i in range(b): if remSq[i] > maxRemSq: maxRemSq = remSq[i] start = i # If max remaining squares = 0 then we have already # cut the entire paper if maxRemSq == 0: return 0 end = start newRemSq = remSq[:] ans = float('inf') # Find the ending point of min height while end < b: # length of edge of square from start till current end squareEdge = end - start + 1 # If the current column does not have maximum remaining # squares or if it's impossible to cut a square of # size squareEdge then break out of the loop if newRemSq[end] != maxRemSq or newRemSq[end] - squareEdge < 0: break # If we can cut a square of size squareEdge # update the remainingSquares for i in range(start end + 1): newRemSq[i] = maxRemSq - squareEdge # Find the solution for new remainingSquares ans = min(ans 1 + minCutUtil(newRemSq a b memo)) end += 1 memo[key] = ans return ans # Function to find the minimum number of squares we can cut # using paper of size a X b def minCut(a b): # if the given rectangle is a square if a == b: return 1 # Initialize remaining squares = a for all the b columns remSq = [a] * b memo = {} return minCutUtil(remSq a b memo) if __name__ == '__main__': # Sample Input a = 13 b = 11 # Function call to get minimum number # of squares for axb print(minCut(a b))
C# // C# Program to find minimum number of squares to cut // from a paper of size axb using System; using System.Collections.Generic; class GfG { // function to get the hash key for remSq array static int getKey(int[] remSq int b) { int baseVal = 1; int key = 0; for (int i = 0; i < b; i++) { key += (remSq[i] * baseVal); baseVal = baseVal * (b + 1); } return key; } // Recursive function to find the minimum number of square cuts // for a given remSq array static int minCutUtil(int[] remSq int a int b Dictionary<int int> memo) { // pointers to mark the start and end of range // with maximum remaining squares int start = 0 end; // Check if we have previously calculated the answer // for the same state int key = getKey(remSq b); if (memo.ContainsKey(key)) return memo[key]; int maxRemSq = 0; // Find the starting point of min height for (int i = 0; i < b; i++) { if (remSq[i] > maxRemSq) { maxRemSq = remSq[i]; start = i; } } // If max remaining squares = 0 then we have already // cut the entire paper if (maxRemSq == 0) return 0; end = start; int[] newRemSq = (int[])remSq.Clone(); int ans = int.MaxValue; // Find the ending point of min height while (end < b) { // length of edge of square from start till current end int squareEdge = end - start + 1; // If the current column does not have maximum remaining // squares or if it's impossible to cut a square of // size squareEdge then break out of the loop if (newRemSq[end] != maxRemSq || newRemSq[end] - squareEdge < 0) break; // If we can cut a square of size squareEdge // update the remainingSquares for (int i = start; i <= end; i++) newRemSq[i] = maxRemSq - squareEdge; // Find the solution for new remainingSquares ans = Math.Min(ans 1 + minCutUtil(newRemSq a b memo)); end += 1; } memo[key] = ans; return ans; } // Function to find the minimum number of squares we can cut // using paper of size a X b static int minCut(int a int b) { // if the given rectangle is a square if (a == b) return 1; // Initialize remaining squares = a for all the b columns int[] remSq = new int[b]; for (int i = 0; i < b; i++) remSq[i] = a; Dictionary<int int> memo = new Dictionary<int int>(); return minCutUtil(remSq a b memo); } static void Main() { int a = 13 b = 11; // Function call to get minimum number // of squares for axb Console.WriteLine(minCut(a b)); } }
JavaScript // JavaScript Program to find minimum number of squares to cut // from a paper of size axb // function to get the hash key for remSq array function getKey(remSq b) { let base = 1; let key = 0; for (let i = 0; i < b; i++) { key += (remSq[i] * base); base = base * (b + 1); } return key; } // Recursive function to find the minimum number of square cuts // for a given remSq array function minCutUtil(remSq a b memo) { // pointers to mark the start and end of range // with maximum remaining squares let start = 0 end; // Check if we have previously calculated the answer // for the same state let key = getKey(remSq b); if (key in memo) return memo[key]; let maxRemSq = 0; // Find the starting point of min height for (let i = 0; i < b; i++) { if (remSq[i] > maxRemSq) { maxRemSq = remSq[i]; start = i; } } // If max remaining squares = 0 then we have already // cut the entire paper if (maxRemSq === 0) return 0; end = start; let newRemSq = remSq.slice(); let ans = Infinity; // Find the ending point of min height while (end < b) { // length of edge of square from start till current end let squareEdge = end - start + 1; // If the current column does not have maximum remaining // squares or if it's impossible to cut a square of // size squareEdge then break out of the loop if (newRemSq[end] !== maxRemSq || newRemSq[end] - squareEdge < 0) break; // If we can cut a square of size squareEdge // update the remainingSquares for (let i = start; i <= end; i++) newRemSq[i] = maxRemSq - squareEdge; // Find the solution for new remainingSquares ans = Math.min(ans 1 + minCutUtil(newRemSq a b memo)); end += 1; } memo[key] = ans; return ans; } // Function to find the minimum number of squares we can cut // using paper of size a X b function minCut(a b) { // if the given rectangle is a square if (a === b) return 1; // Initialize remaining squares = a for all the b columns let remSq = new Array(b).fill(a); let memo = {}; return minCutUtil(remSq a b memo); } // Driver Code let a = 13 b = 11; // Function call to get minimum number // of squares for axb console.log(minCut(a b));
Kimenet
6
Időbonyolultság: O(a^b) minden b oszlophoz lehet egy négyzet.
Segédtér: O(a^b) az egyes egyedi állapotokat tároló memoizáció miatt.
5 db 5 x 8 méretű papírból kivágott négyzet
6 négyzet 13x11 méretű papírból vágva
5 négyzet 6x7 méretű papírból vágva