1. 程式人生 > 其它 >題解P0006:生日蛋糕(P1731)

題解P0006:生日蛋糕(P1731)

這道題居然是1999年省選題!這可能是洛谷藍題裡最水的了。。。

題目連結:https://www.luogu.com.cn/problem/P1731  大家有興趣可以去看看

題目描述:就是類似這樣一個蛋糕:

 

 現在給它體積和層數,為了省奶油,要求它最小表面積(不算底面)

題目思路:深搜剪枝,從下到上列舉每層的半徑和高,最終求出最小表面積(具體思路和剪枝詳見程式碼註釋)

程式碼:

#include<bits/stdc++.h>
using namespace std;
int r[21],h[21],n,m,we=0x3f3f3f3f;//定義陣列儲存半徑和高是為了省事 
void dfs(int v,int s,int k,int p){//v:體積;s:表面積;k和p:層數(一個倒著的一個正著的) 
	int i,j;
	//下面是剪枝,可以最後看 
	if(v<0){//體積超了 
		return;//返 
	} 
	if(k<0){//層數超了 
		return;//返 
	}
	if(s+k+r[1]*r[1]>we){//表面積超了當前最小值,再往下搜沒意義了 
		return;//返 
	}
	if(v>r[p-1]*r[p-1]*h[p-1]*k){//假設之後的體積全=當前體積,還是不夠 
		return;//返 
	}
	//剪枝結束 
	if(k==0&&v==0){//滿足條件 
		s+=r[1]*r[1];//加上最下面的底面積(=所有層有用的底面積) 
		we=min(we,s);//取最小值 
		return;
	}
	for(i=r[p-1]-1;i>=k;i--){//列舉半徑(i的初始值是上一層-1) 
		for(j=h[p-1]-1;j>=k;j--){//列舉高 
			if(v>=i*i*j&&k>=0){
				r[p]=i;
				h[p]=j;
				dfs(v-i*i*j,s+2*i*j,k-1,p+1);//v減去當前層體積,s加上側面積 
				r[p]=i;//回溯 
				h[p]=j;
			}
		}
	}
}
int main(){
	cin>>n>>m;
	h[0]=int(sqrt(n));
	r[0]=int(sqrt(n));//手動確定最底層高和半徑的最大值 
	dfs(n,0,m,1);
	if(we==0x3f3f3f3f){//若值不變 
		cout<<0;//輸出0 
	}else{
		cout<<we;
	}
	return 0; 
}