Ir para o conteúdo

Phidias

Phidias, o conhecido escultor grego, prepara mais uma das suas obras. Para isso, ele precisa de painéis rectangulares de mármore de tamanho C1 x H1, C2xH2, ..., Cn x Hn.

Recentemente, Phidias recebeu uma grande e rectangular peça de mármore, que vai cortar de modo a formar as peças mais pequenas que necessita. Qualquer pedaço de mármore (a peça inicial ou qualquer placa obtida após o primeiro corte) pode ser cortado ou na horizontal, ou na vertical em duas outras placas com largura e altura inteiras. Esta é a única forma de cortar peças, e as peças não podem ser coladas. Como a mármore tem um padrão, as placas não podem ser rodadas: se ele corta uma placa de tamanho A x B, não pode ser usada como uma placa de tamanho B x A (excepto se A = B, obviamente) Ele pode fazer 0 ou mais placas de cada um dos tamanhos pretendidos. (é um monumento bastante grande)

Um pedaço de mármore é desperdiçado se, no final de todos os cortes, não possui as dimensões necessárias. Phidias questiona-se sobre qual a melhor maneira de cortar a peça, de modo a minimizar a área desperdiçada.

Como um exemplo, assumam que na figura que se segue a largura inicial era 21 e a altura 11. Os tamanhos das peças necessárias são: 10x4, 6x2, 7x5, 15x10. A área mínima desperdiçada é 10, e a figura mostra uma possível sequência de cortes com essa área desperdiçada.

Exemplo de solução

O objectivo é fazer um programa que dada uma peça original e as dimensões das placas necessárias, calcule a área mínima desperdiçada.

Explicação de Input

A primeira linha do input contem dois inteiros: L, a largura da placa original, e H, a altura da placa. A segunda linha contem um inteiro, N, o número de diferentes tamanhos possíveis. As seguintes N linhas contém os tamanhos das placas. Cada linha com dois inteiros: Li e Hi, respectivamente a largura e a altura da placa correspondente.

Explicação de Output

Um único inteiro, a área mínima desperdiçada.

Exemplo de input/output

Input

21 11
4
10 4
6 2
7 5
15 10

Output

10

Restrições

O programa deve responder com sucesso a um input que siga estes limites: 1 <= L,H <= 600 1 <= N <= 200 1 <= Li <= L 1 <= Hi <= H

Soluções

C

Solução submetida por warrior.

#include <stdio.h>
#include <string.h>

#define MAX 605

int m[MAX][MAX];

int l,c;

void ler() {
  int n,a,b;
  memset(m,0xFF,sizeof(m));
  scanf("%d %d",&l,&c);
  scanf("%d",&n);
  for (int i=0;i<n;i++) {
    scanf("%d %d",&a,&b);
    m[a][b]=0;
  }
}

void solve() {
  int min;
  for (int i=1;i<=l;i++) {
    for (int j=1;j<=c;j++) {
      if (m[i][j]==0)
    continue;
      min=i*j;
      for (int k=1;k<i;k++) 
    if (min>m[k][j]+m[i-k][j]) 
      min=m[k][j]+m[i-k][j];
      for (int k=1;k<j;k++)
    if (min>m[i][k]+m[i][j-k])
      min=m[i][k]+m[i][j-k];
      m[i][j]=min;
    }
  }
}

int main() {
  ler();
  solve();
  printf("%dn",m[l][c]);
  return 0;
}

C++

Solução submetida por mogers.

#include <iostream>
#include <algorithm>
#include <cstring>
#define MAX 601
using namespace std;

int dp[MAX][MAX];   // desperdicio com uma peca LxH

int calcula( int L , int H ) {
    int & r = dp[L][H] , i ;
    if ( r >= 0 )       return r;     // o desperdicio com estas dimensoes ja foi calculado, retorna o valor da tabela
    if ( L == 0 || H == 0 ) return r = 0; // tamanho 0 e' o mesmo que nada

    r = L * H;  // tudo desperdicado

    for (i = 1 ; i < L ; i++)   // corte horizontal
        r = min( r , calcula( i , H ) + calcula( L-i , H ) );
    for (i = 1 ; i < H ; i++)   // corte vertical
        r = min( r , calcula( L , i ) + calcula( L , H-i ) );
    return r ;
}
int main()
{
    memset( dp , -1 , sizeof(dp) );
    int L , H , N , i , j;
    cin >> L >> H >> N;
    while (N--) {
        cin >> i >> j;
        dp[i][j] = 0;   // pecas com dimensoes necessitadas nao provocam desperdicio
    }
    cout << calcula( L , H ) << endl;
    return 0;
}