日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

石子合并问题

發(fā)布時間:2024/10/6 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 石子合并问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

石子合并問題


石子合并問題是最經(jīng)典的DP問題。首先它有如下3種題型:

(1)有N堆石子,現(xiàn)要將石子有序的合并成一堆,規(guī)定如下:每次只能移動任意的2堆石子合并,合并花費(fèi)為新合成的一堆石子的數(shù)量。求將這N堆石子合并成

分析:當(dāng)然這種情況是最簡單的情況,合并的是任意兩堆,直接貪心即可,每次選擇最小的兩堆合并。本問題實際上就是哈夫曼的變形。

(2)有N堆石子,現(xiàn)要將石子有序的合并成一堆,規(guī)定如下:每次只能移動相鄰的2堆石子合并,合并花費(fèi)為新合成的一堆石子的數(shù)量。求將這N堆石子合并成一堆的總花費(fèi)最小(或最大)。

(3)問題(2)的是在石子排列是直線情況下的解法,如果把石子改為環(huán)形排列,又怎么做呢?

(一)任意合并


題目


(1)有N堆石子,現(xiàn)要將石子有序的合并成一堆,規(guī)定如下:每次只能移動任意的2堆石子合并,合并花費(fèi)為新合成的一堆石子的數(shù)量。求將這N堆石子合并成

分析


當(dāng)然這種情況是最簡單的情況,合并的是任意兩堆,直接貪心即可,每次選擇最小的兩堆合并。本問題實際上就是哈夫曼的變形。

代碼

STL堆算法

#include<iostream> #include<vector> #include<algorithm> using namespace std; int main() {int t;cin>>t;while(t--){int n;cin>>n;vector<int> v;while(n--){int x;cin>>x;v.push_back(x);}long long sum=0;make_heap(v.begin(),v.end(),greater<int>());while(v.size()>1){int min1=v.front();pop_heap(v.begin(),v.end(),greater<int>());v.pop_back();int min2=v.front();pop_heap(v.begin(),v.end(),greater<int>());v.pop_back();//cout<<min1<<" "<<min2<<endl;sum+=(min1+min2);v.push_back(min1+min2);push_heap(v.begin(),v.end(),greater<int>());}cout<<sum<<endl;}return 0; }

STL優(yōu)先隊列?

#include<iostream> #include<queue> //#include<bits/stdc++.h> using namespace std; const int MAX=1e4+5; int n; int main() {ios::sync_with_stdio(false);int t;cin>>t;while(t--){int n,x;cin>>n;priority_queue<int,vector<int>,greater<int> >q;for(int i=0;i<n;i++){cin>>x;q.push(x);}long long sum=0;while(q.size()>1){int min1=q.top();q.pop();int min2=q.top();q.pop();sum+=(min1+min2);q.push(min1+min2);}cout<<sum<<endl;} return 0;}

(二)相鄰合并


題目


有N堆石子,現(xiàn)要將石子有序的合并成一堆,規(guī)定如下:

1.每次只能移動相鄰的2堆石子合并?
2.合并花費(fèi)為新合成的一堆石子的數(shù)量。

求將這N堆石子合并成一堆的總花費(fèi)最小(或最大)。

分析


我們熟悉矩陣連乘,知道矩陣連乘也是每次合并相鄰的兩個矩陣,那么石子合并可以用矩陣連乘的方式來解決。

設(shè)dp[i][j]表示第i到第j堆石子合并的最優(yōu)值,sum[i][j]表示第i到第j堆石子的總數(shù)量。那么就有狀態(tài)轉(zhuǎn)移公式:?

代碼

#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f //#define inf 1<<20 const int maxn=210; int n,a[maxn]; int dp[maxn][maxn];//dp[i][j]表示從第i堆到第j堆合并的代價 int sum[maxn][maxn];//表示石頭的數(shù)量 int main() {ios::sync_with_stdio(0);while(cin>>n){for(int i=1;i<=n;i++)cin>>a[i];memset(sum,0,sizeof(sum));//fill(dp[0],dp[0]+n*n,inf);//錯誤 fill(dp[0],dp[0]+maxn*maxn,inf);//fill填充量必須是常數(shù) for(int i=1;i<=n;i++)sum[i][i]=a[i],dp[i][i]=0;for(int len=1;len<n;len++){//區(qū)間長度 for(int i=1;i<=n&&i+len<=n;i++){//區(qū)間起點(diǎn) int j=i+len;//區(qū)間終點(diǎn)for(int k=i;k<=j;k++)//用k來表示分割區(qū)間 {sum[i][j]=sum[i][k]+sum[k+1][j];dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j]);} }}cout<<dp[1][n]<<endl;}return 0; }

(三)環(huán)形合并


題目


在一個圓形操場的四周擺放著n堆石子(n<= 100),現(xiàn)要將石子有次序地合并成一堆。規(guī)定每次只能選取相鄰的兩堆合并成新的一堆,并將新的一堆的石子數(shù),記為該次合并的得分。

編一程序,讀入石子堆數(shù)n及每堆的石子數(shù)(<=20)。選擇一種合并石子的方案,使得做n-1次合并,得分的總和最小;

比如有4堆石子:4 4 5 9 則最佳合并方案如下:

4 4 5 9 score: 0 8 5 9 score: 8 13 9 score: 8 + 13 = 21 22 score: 8 + 13 + 22 = 43
  • 1
  • 2
  • 3
  • 4

輸入:

可能有多組測試數(shù)據(jù)。 當(dāng)輸入n=0時結(jié)束! 第一行為石子堆數(shù)n(1<=n<=100);第二行為n堆的石子每堆的石子數(shù),每兩個數(shù)之間用一個空格分隔。

輸出:

合并的最小得分,每個結(jié)果一行。

輸入樣例:

4 4 4 5 9?
6 3 4 6 5 4 2?
0

輸出樣例:

43?
61

分析

假設(shè)石頭為a1,a2,a3.....an,首尾相連之后就是 a1,a2,a3.....an,a1,a2,a3....an;序列長度變?yōu)樵瓉淼?倍

?
?
?

#include<bits/stdc++.h> using namespace std; const int maxn=450;//區(qū)間長度為2*n int dp[maxn][maxn]; int sum[maxn];//前綴和數(shù)組 int a[maxn];//每堆石子的個數(shù) int main() {int n,x;sum[0]=0;while(scanf("%d",&n)!=EOF){memset(dp,0,sizeof(dp));memset(sum,0,sizeof(sum));for(int i=1;i<=n;i++){scanf("%d",&a[i]);sum[i]=sum[i-1]+a[i];//預(yù)處理dp[i][i]=0;}int in=1;//首尾相連之后for(int i=n+1;i<=2*n;i++)sum[i]+=(sum[i-1]+a[in++]);for(int len=2;len<=n;len++)//枚舉區(qū)間長度{for(int i=1;i<=2*n;i++)//枚舉區(qū)間起點(diǎn){int j=i+len-1;//區(qū)間終點(diǎn)if(j>n*2) break;//越界結(jié)束for(int k=i;k<j;k++)//枚舉分割點(diǎn),構(gòu)造狀態(tài)轉(zhuǎn)移方程{dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+(sum[j]-sum[i-1]));}}}int MAX=-1;for(int i=1;i<=n;i++)//枚舉環(huán)狀序列的起點(diǎn),長度為nMAX=max(dp[i][i+n-1],MAX);//求最大值printf("%d\n",MAX);}return 0; }

?

總結(jié)

以上是生活随笔為你收集整理的石子合并问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。