1. 程式人生 > >ccf再賣菜

ccf再賣菜

這題一看就是暴搜,想都不想就寫了個暴搜程式(不考慮複雜度),但這題正解應該是記憶化搜尋。。

 

已知a[n],求b[n],其中a[n]是所給資料,b[n]是要求的菜價

其中有 (b[n-1]+b[n]+b[n+1])/3=a[n](n表示第n天菜價)

所以b[n+1]=3*a[n]-b[n-1]-b[n],或b[n+1]=3*a[n]-b[n-1]-b[n]+1,或b[n+1]=3*a[n]-b[n-1]-b[n]+2

有三種結果是因為3的餘數可以是0,1,2

遞推關係式就求出來了,每次用b[n-1],b[n],得出b[n+1],所以用dfs暴搜

這裡要考慮特殊情況,就是第一天和最後一天是除以2,所以寫兩種情況就可以了

其他情況看程式碼註釋吧,。

#include<iostream>
#include<cstdlib>
using namespace std;
int t,count;
int a[400],b[400];//輸入菜價,所求菜價 
bool f[301][301][301]; //儲存狀態資訊,也就是dfs的n,x,y 
void dfs(int n,int x,int y)//分別是搜到第n天,b[n-1](求到了第n-1天的菜價),b[n](求到了第n天的菜價)
{ 
	if(f[n][x][y])return;//剪枝,不加只有80分 
	f[n][x][y]=1;
	if(n==t-1) //最後一天菜價特殊處理,所以n只用等於t-1就夠了 
	{
		if((3*a[n]-x)/2==a[t]||(3*a[n]-x+1)/2==a[t]||(3*a[n]-x+2)/2==a[t]) //最後一天菜價 
		{
			//cout<<count<<endl;
			for(int i=1;i<=n;++i)    //輸出 
			cout<<b[i]<<" ";
			for(int i=0;i<3;++i)
			{
				if((3*a[n]-x+i)/2==a[t]) //輸出最後一天菜價
				{
					cout<<3*a[n]-x-y+i;
					exit(0);  //直接結束程式,這樣用時更短 
				}
			}
		}
		return;
	}
	for(int i=0;i<3;++i) 
	{
		b[n+1]=3*a[n]-x-y+i; //遞推關係式 
		if(b[n+1]>=1)
		dfs(n+1,y,b[n+1]);
	}
}
int main()
{
	cin>>t;
	for(int i=1;i<=t;++i)
	cin>>a[i];
	for(int i=1;i<=2*a[1];++i)
	{
		b[1]=i,b[2]=2*a[1]-i;  //第一天菜價,有兩種可能 
		dfs(2,i,b[2]);
		b[1]=i,b[2]=2*a[1]-i+1; //第二種可能 
		dfs(2,i,b[2]);
	} 
	return 0;
}
/*
290
8 8 7 11 12 11 22 23 23 8 8 5 5 5 5 5 5 5 6 7 7 7 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 
5 6 7 8 8 7 5 5 5 8 25 31 31 15 8 28 28 48 25 25 5 6 7 8 8 7 5 5 5 5 5 5 5 5 5 5 5 5 5 
5 5 6 7 8 8 6 5 5 5 5 5 5 5 21 21 21 5 5 5 5 5 27 28 29 7 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 7 8 8 7 5 5 5 5 5 
5 5 5 5 5 5 5 5 5 5 6 7 8 8 7 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 8 8 7 11 12 11 22 23 23 8
8 8 7 11 12 11 22 23 23 8 8 8 7 11 12 11 22 23 23 8 8 8 7 11 12 11 22 23 23 8
8 8 7 11 12 11 22 23 23 8 8 8 7 11 12 11 22 23 23 8 8 8 7 11 12 11 22 23 23 8
8 8 7 11 12 11 22 23 23 8 8 8 7 11 12 11 22 23 23 8 8 8 7 11 12 11 22 23 23 8
8 8 7 11 12 11 22 23 23 8 8 8 7 11 12 11 22 23 23 8 8 8 7 11 12 11 22 23 23 8
*/

執行次數為199452次,這樣的程式結果只有30分

當加入記錄狀態陣列f[x][y][z]後,執行次數只有1462次,執行時間大大縮短,目前ccf沒放題,還不知道記搜多少分,,,

但粗略的考慮,暴搜時間複雜度為3^n,記搜時間複雜度為n*300*300,應該不會超時。

來年再戰!

剛剛把程式提交了,100分,。