【DP】【递归】分离与合体
分離與合體
題目大意:
有n個區域,可以把它們分為兩個區間,結果加上左邊區間的最左區域的數和最右區域的數還有右邊區間的最右區域的數,就這樣不停分,使結果最大,并輸出各分界線的位置(按1/2,2/4,4/8的順序)
原題:
題目描述
經過在機房里數日的切磋,LYD從杜神牛那里學會了分離與合體,出關前,杜神牛給了他一個測試…
杜神牛造了n個區域,它們緊鄰著排成了一行,編號1~n。在這每個區域里都放著一把OI界的金鑰匙,每一把都有一定的價值,LYD當然想得到它們了。然而杜神牛規定LYD不可以一下子把它們全部拿走,而是每次只可以拿一個。為了盡快的拿到所有的金鑰匙,LYD自然就用上了剛學的分離與合體特技。
一開始LYD可以選擇從1到n-1的任何一個區域(記為K)進入,進入后LYD會在K區域發生分離,從而分離為兩個小LYD。分離完成的同時會有一面墻在K和K+1區域之間升起,從而把1到k和k+1到n阻斷為兩個獨立的區間。然后兩個小LYD分別進入1到k和k+1到n,并在各自的區間內任選除了區間末尾區域以外(即1到k-1或k+1到n-1)的任何一個區域再次發生分離,就一共有了4個小小LYD……重復進行以上所敘述的分離,直到每個小LYD發現自己所在的區間只剩下了一個區域,他們就可以抱起自己夢寐以求的OI金鑰匙。
但是LYD不能就這么分成n多個個體存在于世界上,這些小LYD還會再合體,合體的兩個小LYD所在的區間中間的墻會消失。合體會獲得一定的價值,計算方法是:(合并后所在區間的左右端區域里金鑰匙的價值之和) 乘 (之前分離的時候所在區域的金鑰匙價值)。
{例如:LYD曾經在13區間中的2號區域分離成為12和3兩個區間,合并時獲得的價值就是(1號金鑰匙價值+3號價值)*(2號金鑰匙價值)。}
LYD請你編程求出最終可以獲得的總價值最大是多少。并按照分離階段從前到后,區域從左向右的順序,輸出發生分離的區域編號 (例如:先打印1分為2的分離區域,然后從左到右打印2分為4的分離區域,然后是4分為8的…) 。
注意:若有多種方案,選擇分離區域盡量靠左的方案(也可以理解為輸出字典序最小的)。
輸入
第一行:正整數n (2<=n<=300)
第二行:n個正整數,表示1~n區域里每把金鑰匙的價值。
保證答案及運算過程中不超出longint范圍。
輸出
第一行一個數,即獲得的最大價值
第二行按照分離階段從前到后,區域從左向右的順序,輸出發生分離的區域編號,中間用一個空格隔開,若有多種方案,選擇分離區域盡量靠左的方案(也可以理解為輸出字典序最小的)。
輸入樣例
7 1 2 3 4 5 6 7輸出樣例
238 1 2 3 4 5 6說明
數據范圍約定
對于%20的數據 N<=10
對于%40的數據 N<=50
對于%100的數據 N<=300 a[i]<=300
解題思路:
石子合并改一下,將加上的數改成題意,然后遞歸輸出分界線
代碼:
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int n,k,t,a[305],f[305][305],b[305][3055]; void dg(int x,int y,int dep) {if (x>=y) return;//相交在一起了if (dep==k)//剛好{printf("%d ",b[x][y]);//輸出t=1;//記錄return;}dg(x,b[x][y],dep+1);//左邊dg(b[x][y]+1,y,dep+1);//右邊 } int main() {scanf("%d",&n);for (int i=1;i<=n;++i)scanf("%d",&a[i]);for (int i=n-1;i>0;--i)//石子合并模板for (int j=i+1;j<=n;++j)for (int c=i;c<j;++c)if(f[i][c]+f[c+1][j]+(a[i]+a[j])*a[c]>f[i][j])//想加的東西改成最左加最右乘上中間{f[i][j]=f[i][c]+f[c+1][j]+(a[i]+a[j])*a[c];b[i][j]=c;//記錄}printf("%d\n",f[1][n]);t=1;while(t){t=0;//判斷是否有輸出k++;//分的每一層dg(1,n,1);} }總結
以上是生活随笔為你收集整理的【DP】【递归】分离与合体的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何解决办公室里的辐射问题办公室怎么防辐
- 下一篇: 初一级模拟试题总结(2019.3.2)