POJ 1190 生日蛋糕

題目大意:中文

題目鏈接

註釋代碼:

/*                               
 * Problem ID : POJ 1190 生日蛋糕
 * Author     : Lirx.t.Una                               
 * Language   : C                  
 * Run Time   : 0 ms                               
 * Run Memory : 132 KB                               
*/ 

#include <stdio.h>

#define	INF		0xFFFFFF

#define	POW(x)	( (x) * (x) )
//計算∑n^3 = n^2 * n^2 * (n+1)^2 * (n+1)^2 * 4
#define	SUM3(x)	( ( POW( (x) ) * POW( (x) + 1 ) ) >> 2 )

int		V, F;//輸入的總體積和蛋糕的層數
int		ans;//最終的最小面積,也是搜索過程中的當前最小面積,搜索中不斷更新

int
min( int a, int b ) {

	return a < b ? a : b;
}

void
dfs( int cur_f, int lft_v, int udr_s, int cur_r, int cur_h ) {
	//cur_f,當前所處的層,從下往上進行搜索
	//lft_v,當前還剩下多少體積沒拼完
	//udr_s,under_s,當前層以下(就是之前)已經拼出的表面積

	int		r, h;//當前層試探的半徑和高度
	int		cir_s;//當前層的試探圓面積(由r決定)

	if ( !cur_f ) {//已經到達頂層(頂層是1,超出頂層了)
	
		//如果過剩餘體積全部拼完,並且udr_s更優就跟新ans
		if ( !lft_v && udr_s < ans ) ans = udr_s;
		return ;
	}
	if ( udr_s >= ans ) return ;//剪枝1,如果當前拼出的面積以及大於前幾次的最優解則不必再玩兒了

	//剪枝2
	//如果當前剩餘體積連剩下可能的最小體積都達不到也退出
	//因爲題目要求下層一定要比上層半徑和高度都大,因此一個m層的蛋糕,其最小體積爲1^3 + 2^3...+ m^3
	if ( lft_v < SUM3(cur_f) ) return;

	//剪枝3,如果當前拼出的面積加上剩下可能拼出的最小面積比之前拼出的最小面積還要大也不必再玩兒了
	//剩餘可能拼出的最小面積( lft_v << 1 ) / cur_r其實就是剩餘體積除以當前層的最大面積,cur_r就是當前層可能的最大半徑
	//其實就是將剩下的體積看成一個整個圓柱,這實際上不符合題意,但是這裏使用的是不等式的放縮
	if ( ( udr_s + ( lft_v << 1 ) / cur_r ) >= ans ) return ;

	for ( r = cur_r; r >= cur_f; r-- ) {//從當前給定的半徑開始搜索,半徑最小不能炒股cur_f了
	
		cir_s = r * r;
		if ( cur_f == F ) udr_s = cir_s;//如果當前層是底層,需要算上俯瞰面積
		//題中底面積不要求,但是要求俯瞰面積

		//剪枝4
		//可以通過( lft_v - SUM3( cur_f - 1 ) ) / cir_s得到一個該層高度的上界,避免多餘的搜索
		//因爲上面的所有層最大可能體積就是SUM3( cur_f - 1 ),所以當前層可能的最大體積就是lft_v - SUM3( cur_f - 1 )
		//除以一下cir_s就是最大可能的高度
		h = min( cur_h, ( lft_v - SUM3( cur_f - 1 ) ) / cir_s );
		for ( ; h >= cur_f; h-- )//高度最小不能超過cur_f
			dfs( cur_f - 1,
				 lft_v - cir_s * h,
				 udr_s + ( ( r * h ) << 1 ),
			     r - 1, h - 1 );
	}
}

int
main() {

	ans = INF;
	scanf("%d%d", &V, &F); 

	//由於總體積最大爲10000
	//極端情況下就一層,如果高度爲1,則半徑達到最大100,如果半徑爲1則高度達到最大10000
	dfs( F, V, 0, 100, 10000 );
	
	if ( INF == ans ) puts("0");//無解
	else printf("%d\n", ans);

	return 0;
}
無註釋代碼:

#include <stdio.h>

#define	INF		0xFFFFFF

#define	POW(x)	( (x) * (x) )
#define	SUM3(x)	( ( POW( (x) ) * POW( (x) + 1 ) ) >> 2 )

int		V, F;
int		ans;

int
min( int a, int b ) {

	return a < b ? a : b;
}

void
dfs( int cur_f, int lft_v, int udr_s, int cur_r, int cur_h ) {

	int		r, h;
	int		cir_s;

	if ( !cur_f ) {
	
		if ( !lft_v && udr_s < ans ) ans = udr_s;
		return ;
	}
	if ( udr_s >= ans ) return ;
	if ( lft_v < SUM3(cur_f) ) return;
	if ( ( udr_s + ( lft_v << 1 ) / cur_r ) >= ans ) return ;

	for ( r = cur_r; r >= cur_f; r-- ) {
	
		cir_s = r * r;
		if ( cur_f == F ) udr_s = cir_s;

		h = min( cur_h, ( lft_v - SUM3( cur_f - 1 ) ) / cir_s );
		for ( ; h >= cur_f; h-- )
			dfs( cur_f - 1,
				 lft_v - cir_s * h,
				 udr_s + ( ( r * h ) << 1 ),
			     r - 1, h - 1 );
	}
}

int
main() {

	ans = INF;
	scanf("%d%d", &V, &F); 

	dfs( F, V, 0, 100, 10000 );
	
	if ( INF == ans ) puts("0");
	else printf("%d\n", ans);

	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章