logo

Carta tagliata in un numero minimo di quadrati

Data una carta rettangolare di dimensioni unxb . Il compito è tagliare l'intero foglio nel formato minimo numero di piazza pezzi. Possiamo scegliere pezzi quadrati di qualsiasi dimensione ma devono essere tagliati senza sovrapporsi o lasciare spazio aggiuntivo .

Esempi:  

Ingresso: a = 5 b = 8



Carta tagliata nel numero minimo di quadrati 1' title=5 quadrati ritagliati da carta di formato 5 X 8

Produzione: 5
Spiegazione: Possiamo tagliare la carta in 5 quadrati: 1 quadrato di misura 5x5 1 quadrato di misura 3x3 1 quadrato di misura 2x2 e 2 quadrati di misura 1x1.

Ingresso: a = 13 b = 11

Carta tagliata nel numero minimo di quadrati 2' loading='lazy' title=6 quadrati ritagliati da carta di formato 13 X 11

Produzione: 6
Spiegazione: Possiamo tagliare la carta in 6 quadrati: 1 quadrato di misura 7x7 1 quadrato di misura 6x6 1 quadrato di misura 5x5 2 quadrati di misura 4x4 e 1 quadrato di misura 1x1.

inserendo la stringa in Java

Ingresso: a = 6 b = 7

Carta tagliata nel numero minimo di quadrati 3' loading='lazy' title=5 quadrati ritagliati da carta di formato 6 X 7

Produzione: 5
Spiegazione: Possiamo tagliare la carta in 5 quadrati: 1 quadrato di misura 4x4 2 quadrati di misura 3x3 e 2 quadrati di misura 3x3.

scanner java

Sommario

[Approccio Errato 1] Usare la Tecnica Greedy

A prima vista potrebbe sembrare che il problema possa essere facilmente risolto tagliando prima il quadrato più grande possibile dalla carta, poi tagliando il quadrato più grande dalla carta rimanente e così via fino a tagliare l'intera carta. Ma questa soluzione non è corretta.

Perché l'approccio goloso non funziona?

Considera un foglio di formato 6x7 poi se proviamo a tagliare avidamente la carta otterremo 7 quadrati: 1 quadrato di dimensione 6x6 e 6 quadrati di dimensione 1x1 mentre la soluzione corretta è: 5. Quindi l'approccio avido non funzionerà.

[Approccio Errato 2] Utilizzo della Programmazione Dinamica

Programmazione dinamica con tagli verticali o orizzontali: Un'altra soluzione che potrebbe sembrare corretta è l'utilizzo Programmazione dinamica . Possiamo mantenere una tabella dp[][] tale che dp[i][j] = numero minimo di quadrati ritagliabili dalla carta di formato io x j . Quindi per la carta di formato axb

  • Possiamo provare a tagliarlo lungo ogni riga: dp[i][j] = min(dp[i][j] 1 + dp[i - k][j] + dp[k][j]) dove k può essere compreso nell'intervallo [1 i - 1].
  • Possiamo provare a tagliarlo lungo ciascuna colonna: dp[i][j] = min(dp[i][j] 1 + dp[i][j - k] + dp[i][k]) dove k può essere compreso nell'intervallo [1 j - 1].

Alla fine la risposta sarà il minimo dei tagli. Ma anche questa soluzione è sbagliata.

Perché tagliare verticalmente o orizzontalmente con l'approccio di programmazione dinamica non funziona?

Questo non funzionerà perché presupponiamo che un taglio verticale o orizzontale dividerà sempre il rettangolo in due parti. Considera un foglio di formato 13x11 quindi se proviamo a tagliare la carta utilizzando l'approccio DP otterremo 8 quadrati ma la risposta corretta (come mostrato negli esempi) è 6. Quindi la programmazione dinamica non funzionerà.

[Approccio corretto] Utilizzo di DFS e programmazione dinamica

IL idea è tagliare l'intera carta usando DFS In dal basso verso l'alto maniera. Ad ogni passaggio, trova l'angolo in basso a sinistra del foglio e prova a tagliare quadrati di tutte le dimensioni possibili da quell'angolo. Dopo aver tagliato nuovamente un quadrato, trova l'angolo inferiore sinistro della carta rimanente per tagliare quadrati di tutte le dimensioni possibili e così via. Ma se provassimo tutti i possibili tagli dall'angolo inferiore sinistro di ogni possibile formato carta, sarebbe del tutto inefficiente. Possiamo ottimizzarlo utilizzando Programmazione dinamica per memorizzare i tagli minimi per ogni possibile formato carta.

Per identificare in modo univoco qualsiasi dimensione del foglio possiamo mantenere un array remSq[] tale che remSq[i] memorizzi il numero di quadrati rimanenti di dimensione 1x1 nell'i-esima colonna del foglio. Quindi per un foglio di dimensioni 6x7 remSq[] = {6 6 6 6 6 6 6}. Anche per trovare l'angolo in basso a sinistra troveremo il primo indice avente il massimo dei quadrati rimanenti. Quindi possiamo eseguire l'hashing del valore dell'array remSq[] per trovare una chiave univoca per tutti i possibili valori dell'array remSq[].

test delle prestazioni
C++
// 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)); 

Produzione
6

Complessità temporale: O(a^b) per ciascuna delle b colonne possiamo avere un quadrato.
Spazio ausiliario: O(a^b) grazie alla memorizzazione di ogni stato univoco.