经过几天的研究。。。终于完成了生日蛋糕~(noi99)
剪枝非常明显~
注意:
2*(n-v)/r+s>=opt,不能写成2/r*(n-v)+s,之前犯了这个错误,就tle,估计还可能是死循环。。。
main函数里就不要用for循环了,用了也会tle.
3个重要的剪枝:
当已有体积加上剩余的最小体积大于总体积时剪枝;
当已有面积加上剩余最小体积大于当前最优面积时剪枝;
当2倍的剩余体积除以当前半径加上已有面积大于当前最优面积时剪枝( 2*(n-v)/r+s>=opt) ,证明,略;
剪枝非常明显~
注意:
2*(n-v)/r+s>=opt,不能写成2/r*(n-v)+s,之前犯了这个错误,就tle,估计还可能是死循环。。。
main函数里就不要用for循环了,用了也会tle.
3个重要的剪枝:
当已有体积加上剩余的最小体积大于总体积时剪枝;
当已有面积加上剩余最小体积大于当前最优面积时剪枝;
当2倍的剩余体积除以当前半径加上已有面积大于当前最优面积时剪枝( 2*(n-v)/r+s>=opt) ,证明,略;
- #include<iostream>
- using namespace std;
- const int oo = 1e10;
- int mins[21],minv[21],m,n,opt;
- void solve ( int v ,int s ,int level , int r , int h )
- {
- int i,j,hh;
- if ( level==0 )
- {
- if ( v==n && s<opt )
- opt=s;
- return;
- }
- if ( v+minv[level-1]>n || s+mins[level-1]>opt || 2*(n-v)/r+s>=opt )
- return ;
- for ( i=r-1 ; i>=level ; i-- )
- {
- if ( level==m )
- s=i*i;
- hh=min((n-v-minv[level-1])/(i*i),h-1);
- for ( j=hh ; j>=level ; j-- )
- solve(v+i*i*j,s+2*i*j,level-1,i,j);
- }
- }
- int main ( )
- {
- int i;
- scanf("%d%d",&n,&m);
- opt=oo;
- for(i=1,minv[0]=mins[0]=0;i<21;i++)
- {
- mins[i]=mins[i-1]+2*i*i;
- minv[i]=minv[i-1]+i*i*i;
- }
- solve(0,0,m,n+1,n+1);
- if ( opt==oo )
- printf("0/n");
- else
- printf("%d/n",opt);
- }