切纸术(动归)——锯钢条二维版
题目:
有一张N*M的矩形白纸,要求切出A*B的纸条若干张,问最多能切出几张!(注:现实中的切纸机一刀必定切断纸,也就是说在切的过程中始终保持纸是矩形的!)
输入
N M A B N,M>A,B>0 0<N,M<1000
输出
X(即最多的白纸数)
因为这个题是我生活中碰见的问题,正好因为最近竞赛学了动归,就拿来解一解,没想到还真让我弄出来了,希望看见的大神们改进改进。
我的想法就是经典的动归,先记录我每次能切的步长放入数组b中,然后对横着切b[i],i=0,1,2....或竖着切做决策,方程出来就简单了,这里我因技术不过关,写的是递归,不过加了缓存时间上也差不多和递推一样。
#include <stdio.h>
#define maxc(x,y) ((x)=(x)<(y)?(y):(x))
int buf[2000][2000];
int b[500];
int inl,ink,cutl,cutk;
int bn;
int back(const void * p1,const void * p2)
{
return (*((int *)p1))-(*((int *)p2));
}
int fun(int l,int k)
{
int i,j,bi;
int max;
if(l*k<cutl*cutk)return 0;
if(l<cutk||k<cutk)return 0;
if(k<cutl&&l<cutl)return 0;
if(l==cutl&&k==cutk)return 1;
if(l==cutk&&k==cutl)return 1;
else
{
max=0;
for(bi=1;bi<bn;bi++)
{
if(k-b[bi]>0)
{
maxc(max,(buf[l][k-b[bi]]?buf[l][k-b[bi]]:fun(l,k-b[bi]))+(buf[l][b[bi]]?buf[l][b[bi]]:fun(l,b[bi])));
}
if(l-b[bi]>0)
{
maxc(max,(buf[l-b[bi]][k]?buf[l-b[bi]][k]:fun(l-b[bi],k))+(buf[b[bi]][k]?buf[b[bi]][k]:fun(b[bi],k)));
}
}
buf[l][k]=max;
buf[k][l]=max;
return max;
}
}
int main(){
int i,j;
scanf("%d%d%d%d",&inl,&ink,&cutl,&cutk);
if(inl<ink)inl^=ink^=inl^=ink;
if(cutl<cutk)cutl^=cutk^=cutl^=cutk;
for(i=1;i*cutl<inl;i++)
{
b[i]=i*cutl;
}
for(j=1;j*cutk<inl;i++,j++)
{
b[i]=j*cutk;
}
bn=i;
qsort(b,bn,4,back);
printf("%d",fun(inl,ink));
return 0;
}