首页 > 代码库 > 石子合并问题
石子合并问题
有若干堆石子,每次只能合并相邻石子堆,每次合并的开销是两堆石子总和。求合并所有石子的最小开销。
首先有一个算法叫GarsiaWachs。这个算法思想是,当有三堆石子 a,b,c,其合并开销有两种:先合并ab,(a+b)+((a+b)+c),先合并bc,(b+c)+((b+c)+a)=>a,c即判断a和c的大小关系。当a<c,就应该先合并ab。故我们从左向右遍历是否有a<c,有的话就合并ab。然后把它插到左边比它大的第一个数右边(这个操作不会影响答案,大家可以自己证明以下)。反复上述操作,最后结果就是最佳方案后的一堆石子了。为了编码方便,我们一般把数组的0和n+1置为inf(石子堆编号从1~n)。
据说可以用平衡树优化,等我去看平衡树再来更新一波。
#include <iostream> #include <string> #include <vector> #include <cmath> #include <algorithm> #include <stack> using namespace std; const int inf=9999999; int main(int argc, char *argv[]) { cin.sync_with_stdio(false); int n; int num[205]; int dp[205]; while(cin>>n) { num[0]=num[n+1]=inf; for(int i=1;i<=n;i++) cin>>num[i]; int ans=0; while(n!=1) { //cout<<n<<endl; for(int i=1;i<=n;i++) { if(num[i-1]<=num[i+1]) { //cout<<num[i-1]<<‘ ‘<<num[i+1]<<endl; num[i-1]+=num[i]; ans+=num[i-1]; for(int j=i+1;j<=n;j++) num[j-1]=num[j]; num[n]=inf; n--; int temp=num[i-1]; for(int j=i-1;j>0;j--) { if(num[j-1]<temp) num[j]=num[j-1]; else { num[j]=temp; break; } } break; } } } cout<<ans<<endl; } return 0; }
还有种算法是基于动态规划的,如果我们要合并i~j堆石子,其开销设为dp[i][j],dp[i][j]=min(dp[i+1][k]+dp[k+1][j]+sum(i,j)) (i<=k<=j)。当区间小到3\2\1我们就可以直接做出决策了。
石子合并问题
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。