CCF 201809 4 試題名稱 再賣菜

2021-09-12 06:23:08 字數 3297 閱讀 1966

參考部落格:201809-4 再賣菜 ccf 剪枝優化

題目就不貼了。

題目要求:給出商店的第二天的菜價,第二天的菜價是第一天臨近商店的**的平均值(求平均時使用去尾法求整),要求找到符合要求的第一天菜價中字典序最小的一種。下面分別使用a,b

a,ba,

b表示第一天,第二天的菜價,由題意可得,菜價應滿足下列不等式:(因為**是整數,所以將等式右邊的值減一,則可將原來的 <

<

<

換為 ≤

\le≤)

2 b1

≤a1+

a2

<2(

b1+1

)→2b

1≤a1

+a2≤

2b1+

12b_1 \le a_1+a_2 < 2(b_1+1) \ \rightarrow \ 2b_1 \le a_1+a_2 \le 2b_1+1 \

2b1​≤a

1​+a

2​<2(

b1​+

1)→2

b1​≤

a1​+

a2​≤

2b1​

+13 b2

≤a1+

a2+a

3≤3b

1+

23b_2 \le a_1+a_2+a_3 \le 3b_1+2

3b2​≤a

1​+a

2​+a

3​≤3

b1​+23b

3≤a2

+a3+

a4≤3

b3+2

3b_3 \le a_2+a_3+a_4 \le 3b_3+2

3b3​≤a

2​+a

3​+a

4​≤3

b3​+2⋅⋅

⋅···

⋅⋅⋅⋅⋅⋅

⋅····

⋅⋅⋅⋅

3 bn

−1≤a

n−2+

an−1

+an≤

3bn−

1+

23b_ \le a_+a_+a_ \le 3b_+2

3bn−1​

≤an−

2​+a

n−1​

+an​

≤3bn

−1​+22b

n≤an

−1+a

n≤2b

n+

12b_ \le a_+a_ \le 2b_+1

2bn​≤a

n−1​

+an​

≤2bn

​+1思路一:純dfs(80分):現在約束已經有了,等式左右兩邊的值都是已知的,最直接的想法就是從小到大列舉a

1a_1

a1​可能的取值(要求字典序最小所以對於任意a

ia_i

ai​的取值都應從小到大列舉),a

1a_1

a1​確定後再根據第乙個不等式考慮a

2a_2

a2​可能的取值,a

2a_2

a2​確定後考慮a

3a_3

a3​····,這樣不斷進行下去,最後如果a

na_n

an​的值也滿足要求,則當前的序列就是所需的字典序最小的序列。

思路二:dfs+剪枝(100分):第乙個方法的問題在於每次嘗試都要計算到第n天或者遇到中間某天沒有可能的取值時才能得出本次嘗試的結果,當n比較大時就會因為可能的情況太多而超時。為了減少嘗試的次數,可以使用記憶化剪枝的方法。

具體來說就是使用變數isfind表示是否已找到最小字典序序列,用visit[i][curr][pre] 陣列來表示 第i天的菜價設為curr,第i-1天設為pre 這種情況是否已經嘗試過,如果嘗試過就直接返回(不再進行嘗試),沒有嘗試過才執行後面的。下面說一下為什麼這種方法有效,一開始可能會認為為了求字典最小的序列我們的嘗試的取值都是從小到大的,怎麼可能存在嘗試過的再一次被嘗試?這個問題的答案就是:我們嘗試第i天的取值時的確是從小到大進行嘗試,當第i天的取值為a時,對於第i+1,i+2兩天,假設它們的取值為b,c,假設這種嘗試不滿足題目要求,函式會返回(此時isfind的值為false),接下來第i天的值被設為a+1,對於第i+1,i+2天,假設它們又分別被設定為了b,c,這次我們就能確定這種嘗試是沒有必要的,因為之前嘗試過了,並沒有找到可行的解(如果之前找到可行解程式已經退出),所以可以不用再進行嘗試,通過這種方式就能較少嘗試的次數,從而避免超時。

下面是兩種思路的**。

思路一**(80分):

#include

using

namespace std;

int d1[

305]

,d2[

305]

;int n;

// 第i天的**設為value是否可能

bool

isvalid

(int i,

int value)

else

if(i ==1)

}else

return

false;}

void

solve()

}int

main

(int argc,

char

const

*ar**)

思路二**(100分):

#include

using

namespace std;

const

int maxn =

400;

int n;

int day1[maxn]

,day2[maxn]

;bool visit[maxn]

[maxn]

[maxn]

;bool isfind =

false

;void

dfs(

int i,

int curr,

int pre)

}else}}

intmain

(int argc,

char

const

*ar**)

for(

int i =

1;i <= n; i++

) cout << day1[i]

<<

" ";

cout << endl;

return0;

}

ccf 201809 4 再賣菜 70分暴力

思路是深搜,然後根據他給的 約束可以取的值減小一點複雜度,最後選夠了之後計算並與答案相比較,由於是從一開始搜的,那麼答案一定是字典序最小的,考試的時候打了個這個才30分,現在變成了70分,鬱悶啊.加上這四十分我就差十分就會程式設計了.話說這次第三題沒寫,第四題可能是敲錯了?第五題暴力20分.簡直就是...

ccf 2018 09 4 再賣菜,記憶化搜尋

問題描述 在一條街上有n個賣菜的商店,按1至n的順序排成一排,這些商店都賣一種蔬菜。第一天,每個商店都自己定了乙個正整數的 店主們希望自己的菜價和其他商店的一致,第二天,每一家商店都會根據他自己和相鄰商店的 調整自己的 具體的,每家商店都會將第二天的菜價設定為自己和相鄰商店第一天菜價的平均值 用去尾...

ccf 201712 2 試題名稱 遊戲

問題描述 有n個小朋友圍成一圈玩遊戲,小朋友從1至n編號,2號小朋友坐在1號小朋友的順時針方向,3號小朋友坐在2號小朋友的順時針方向,1號小朋友坐在n號小朋友的順時針方向。遊戲開始,從1號小朋友開始順時針報數,接下來每個小朋友的報數是上乙個小朋友報的數加1。若乙個小朋友報的數為k的倍數或其末位數 即...