洛谷 P1464 Function

題目描述

對於一個遞歸函數w(a,b,c)w(a,b,c)

  • 如果a≤0 or b≤0 or c≤0就返回值11.
  • 如果a>20 or b>20 or c>20就返回w(20,20,20)
  • 如果a<b並且b<c 就返回w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c)
  • 其它的情況就返回w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1)

這是個簡單的遞歸函數,但實現起來可能會有些問題。當a,b,c均爲15時,調用的次數將非常的多。你要想個辦法才行.

/* absi2011 : 比如 w(30,-1,0)既滿足條件1又滿足條件2

這種時候我們就按最上面的條件來算

所以答案爲1

*/

輸入格式

會有若干行。

並以-1,-1,-1−1,−1,−1結束。

保證輸入的數在[-9223372036854775808,9223372036854775807]之間,並且是整數。

輸出格式

輸出若干行,每一行格式:

w(a, b, c) = ans

注意空格。

輸入輸出樣例

輸入 #1複製

1 1 1
2 2 2
-1 -1 -1

輸出 #1複製

w(1, 1, 1) = 2
w(2, 2, 2) = 4

說明/提示

記憶化搜索

解答:(因爲直接用DP+記憶化就好,思路比較簡單,直接代碼)

/*思路:記憶化*/ 
#include <cstdio>

typedef long long LL;

const int MAX = 21*21*21;		
/*MAX = 20*20*20  error_1:這是我之前的寫法,錯誤點在於,abc <= 20,則應當用21  進制才行*/

int mems[MAX];						//memorys
bool flags[MAX];

int get_index(int a,int b,int c)	//對 a,b,c hash
{	return a*21*21 + b*21 + c;	}

int w(int a,int b,int c){
	//設置出口 
	if(a <= 0||b <= 0||c <= 0)	return 1;
	
	//記憶化
	int index = get_index(a,b,c);
	if(flags[index])	return mems[index]; 
	
	//遞歸過程 
	if(a < b&&b < c)
		mems[index] = w(a,b,c-1) + w(a,b-1,c-1) - w(a,b-1,c);
	else
		mems[index] = w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
		
	flags[index] = true;
	return mems[index];
}

int main()
{
	LL a,b,c;
	int ans;
	while(scanf("%lld %lld %lld",&a,&b,&c)){
		if(a == -1&&b == -1&&c == -1)	break;
		else if(a <= 0||b <= 0||c <= 0)	ans = 1;
/*error2:我沒寫這條語句。題目要求同時滿足條件1、2時,所以在判斷2前要先判斷1。因爲讀入的abc可能是long long型,而真正用到的其實是小於21的數,所以我爲了函數傳參時可以傳int型將判斷2的語句提了出來,之後才導致忘了在其之前+判斷1的語句。*/
/*error3:此處還發生了一個錯誤就是,多出了一個判斷,而之前我的輸出語句是寫在else下的,多了這個條件之後,當這條判斷成功時不會輸出內容了。*/  
		else{
			if(a > 20||b > 20||c > 20)	
				ans = w(20,20,20);
			else
				ans = w(a,b,c);
		}
		printf("w(%lld, %lld, %lld) = %d\n",a,b,c,ans);
/*error4:同error3,自己將輸出語句寫在了else內(因爲當時if中直接break了,所以覺得寫在else裏沒問題),導致多出一個判斷的時候存在有的情況沒有輸出。*/
	} 
	return 0;
}

總結:(針對犯得錯誤)

總的說來,犯得錯誤分爲兩種,一種是讀題不清,另一種是代碼問題,下面說說解決辦法。

讀題不清:

首先第一遍讀題肯定不可能什麼時候都面面俱到,因爲還是要以完成功能爲前提。但是可以在完成要求的同時針對題目的一個一個要求多考察細節,所以解決辦法分兩步。

第一步:對於有些難度的題,多用函數將各功能分離,因爲題目的要求也是一步步來的,針對每個函數去對應地仔細看題目要求。

第二部:在完成之後,要大致再對應題目看一遍,不能只依賴樣例,這樣總是會形成以樣例爲標準而忽略題目要求。

代碼問題:

代碼問題中又有兩個問題,一是自己的代碼潔癖,二是對題目要求是否徹底落實。

代碼潔癖的問題要引起自己的重視,自己總是爲了避免重複代碼和爲了機器節省空間和操作,總是想把代碼寫的很簡潔,但這樣有時會太可以使得自己忽略了本身要實現的功能,所以以後先用自己最有把握實現問題的方式寫,當完全通過之後再試着將剛纔想改進的地方改進,這樣慢慢熟悉了簡單的寫法之後再在做題中使用。

對題目是否落實的問題其實在解決了代碼潔癖的問題和讀題不清的問題之後其實就解決了十之八九了。

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