CCF 再賣菜 100分

關於怎麼從40分---->70分----->100分,我在代碼裏面的註釋部分都寫明瞭。

問題描述

  在一條街上有n個賣菜的商店,按1至n的順序排成一排,這些商店都賣一種蔬菜。
  第一天,每個商店都自己定了一個正整數的價格。店主們希望自己的菜價和其他商店的一致,第二天,每一家商店都會根據他自己和相鄰商店的價格調整自己的價格。具體的,每家商店都會將第二天的菜價設置爲自己和相鄰商店第一天菜價的平均值(用去尾法取整)。
  注意,編號爲1的商店只有一個相鄰的商店2,編號爲n的商店只有一個相鄰的商店n-1,其他編號爲i的商店有兩個相鄰的商店i-1和i+1。
  給定第二天各個商店的菜價,可能存在不同的符合要求的第一天的菜價,請找到符合要求的第一天菜價中字典序最小的一種。
  字典序大小的定義:對於兩個不同的價格序列(a1, a2, ..., an)和(b1, b2, b3, ..., bn),若存在i (i>=1), 使得ai<bi,且對於所有j<i,aj=bj,則認爲第一個序列的字典序小於第二個序列。

輸入格式

  輸入的第一行包含一個整數n,表示商店的數量。
  第二行包含n個正整數,依次表示每個商店第二天的菜價。

輸出格式

  輸出一行,包含n個正整數,依次表示每個商店第一天的菜價。

樣例輸入

8
2 2 1 3 4 9 10 13

樣例輸出

2 2 2 1 6 5 16 10

數據規模和約定

  對於30%的評測用例,2<=n<=5,第二天每個商店的菜價爲不超過10的正整數;
  對於60%的評測用例,2<=n<=20,第二天每個商店的菜價爲不超過100的正整數;
  對於所有評測用例,2<=n<=300,第二天每個商店的菜價爲不超過100的正整數。
  請注意,以上都是給的第二天菜價的範圍,第一天菜價可能會超過此範圍。

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<sstream>
using namespace std;
const int MAXN = 305; 

int n;  //一共有n家店 
int ans[MAXN] = {-1,-1};  //最終的答案 (第一天的菜價) 
int a[MAXN];  //第一天的菜價 (臨時的) 
int b[MAXN];  //第二天的菜價 

void replace(){  //根據字典序進行替換 
	bool flag = false;
	if(ans[1] == -1){
		flag = true;
	}else{
		for(int i=1;i<=n;i++){
			if(a[i] < ans[i]){
				flag = true;
				break;
			}else if(a[i] > ans[i]){
				break;
			}
		}
	}
	if(flag){
		for(int i=1;i<=n;i++){
			ans[i] = a[i];
		}
	}
}

//進行剪枝,沒有rem數組進行剪枝的話會超時,只得了40分。 
//rem[u][x][y]表示:我們是否通過第二天第u家店的菜價和第一天第u-1家和第u家的菜價進行過DFS遞歸
//如果進行過,就說明後面的DFS遞歸跟前面某次的DFS遞歸是重複的,最後勢必得到同樣的答案,就不用進行下去了。 
bool rem[MAXN][MAXN][MAXN];   

/*
** 參數: 
** u: 第二天的第u個店
** x: 第一天的第u-1個店的菜價
** y: 第一天的第u個店的菜價 
**  
** 當前層DFS的功能: 
** 通過第二天第u個店的菜價 
** 和第一天第u-1個店的菜價x
** 和第一天第u個店的菜價y
** 來計算第一天第u+1個店的菜價 
*/ 
void DFS(int u,int x,int y){
	//進行剪枝,沒有rem數組進行剪枝的話會超時,只得了40分。 
	if(rem[u][x][y]){  
		return ;
	}
	rem[u][x][y] = true;
	if(u == n){
		/*
		**這個時候我們已經把第一天每個商家的菜價求出來了,
		**但是需要用下面的兩個if語句把第n家的菜價檢查一下  
		*/
		int sum = b[n-1]*3 - a[n-2];
		/*
		** 這個外層if語句其實我不是很理解,一開始我是沒有這一層判斷的
		** 我覺得我在前面求得時候就已經符合這個if條件的要求
		** 但是不加的話結果就只有70分,加上之後就100分了。 
		*/  
		if( (sum/2)==b[n] || (sum+1)/2==b[n] || (sum+2)/2==b[n]){
			//第一天第n-1家商店菜價(a[n-1])和第n家商店菜價(a[n])的平均值爲b[n] 
			/*
			** 這個if語句是因爲:
			** 我們在計算第一天第n家店的菜價(a[n])時,只通過a[n-1],a[n-2]和b[n-1]衡量過
			** 但是並沒有通過a[n-1]和b[n]衡量過。 
			*/
			if(a[n] + a[n-1]>=2*b[n] && a[n]+a[n-1]<=2*b[n]+1){   
				replace();
				return ;
			}
		}
	}
	for(int sum=b[u]*3;sum<=b[u]*3+2;sum++){
		a[u+1] = sum - a[u] - a[u-1];
		if(a[u+1] <= 0){
			continue;
		}
		DFS(u+1,a[u],a[u+1]);		
	}
} 

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>b[i];
	}
	for(int sum=b[1]*2;sum<=b[1]*2+1;sum++){
		for(int x=1;x<sum;x++){
			a[1] = x;
			a[2] = sum - x;
			DFS(2,a[1],a[2]);	
		}
	}
	for(int i=1;i<n;i++){
		cout<<ans[i]<<" ";
	}
	cout<<ans[n]<<endl;
	return 0; 
} 

 

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