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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【动态规划】 石子合并问题(环形) (ssl 1597)

發布時間:2023/12/3 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【动态规划】 石子合并问题(环形) (ssl 1597) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

石子合并問題石子合并問題

Description

在一個圓形操場的四周擺放著n 堆石子。現要將石子有次序地合并成一堆。規定每次只能選相鄰的2 堆石子合并成新的一堆,并將新的一堆石子數記為該次合并的得分。試設計一個算法,計算出將n堆石子合并成一堆的最小得分和最大得分。

編程任務:

對于給定n堆石子,編程計算合并成一堆的最小得分和最大得分。

Input

輸入包括多組測試數據,每組測試數據包括兩行。

第1 行是正整數n,1<=n<=100,表示有n堆石子。

第2行有n個數,分別表示每堆石子的個數。

Output

對于每組輸入數據,輸出兩行。

第1 行中的數是最小得分;第2 行中的數是最大得分。

Sample Input

4

4 4 5 9

Sample Output

43

54

題目大意:

有n堆石子,圍成一個環,可以將相鄰的兩堆合在一起,兩堆的重量之和為你的分數,要求最大分數和最小分數

解題方法:

建議先做完石子合并(非環形)題解,再做此題,本體我們有兩種方法:

方法一方法一

我們先用一個二位數組f[i][j]來表示從第i對開始,后面的j個數的最小值(最大的用l),然后在后面復制一遍接下來就和石子合并差不多了

動態轉移方程:

f[i][len]=min(f[i][len],f[i][k]+f[i+k][len?k]+s[i+len?1]?s[i?1])f[i][len]=min(f[i][len],f[i][k]+f[i+k][len-k]+s[i+len-1]-s[i-1])f[i][len]=min(f[i][len],f[i][k]+f[i+k][len?k]+s[i+len?1]?s[i?1])
l[i][len]=max(l[i][len],l[i][k]+l[i+k][len?k]+s[i+len?1]?s[i?1])l[i][len]=max(l[i][len],l[i][k]+l[i+k][len-k]+s[i+len-1]-s[i-1])l[i][len]=max(l[i][len],l[i][k]+l[i+k][len?k]+s[i+len?1]?s[i?1])

注釋:

f[i][k]為前面,i+k是后面的開始,len-k是長度有len已經用了k,所以要減掉k,i+len-1是這一段的后面,因為第i個也要求,所以要減去i-1

#include<cstdio> #include<iostream> using namespace std; int a[205],f[205][205],l[205][205],s[205],n,minn,maxx; int main() {memset(f,127/3,sizeof(f));scanf("%d",&n);for (int i=1;i<=n;i++){scanf("%d",&a[i]);s[i]=s[i-1]+a[i];f[i][1]=0;}for (int i=n+1;i<=n*2;i++){s[i]=s[i-1]+a[i-n];//復制一遍f[i][1]=0;}for (int len=2;len<=n;len++)//長度for (int i=1;i<=n*2-len;i++)//前面的數,n-len+1+n-1=n*2-lenfor (int k=1;k<len;k++)//分界線{f[i][len]=min(f[i][len],f[i][k]+f[i+k][len-k]+s[i+len-1]-s[i-1]);//求最小的l[i][len]=max(l[i][len],l[i][k]+l[i+k][len-k]+s[i+len-1]-s[i-1]);//求最大的}minn=2147483647;for (int i=1;i<=n;i++){minn=min(minn,f[i][n]);//最小的maxx=max(maxx,l[i][n]);//最大的}printf("%d\n%d",minn,maxx); }

方法二方法二

我們不在后面加一段(f和l表示的一樣),直接用mod的方法,超過你的直接從1開始往后,本做法詳情看動態轉移方程

動態轉移方程

f[i][len]=min(f[i][len],f[i][k]+f[(i+k?1)modn+1][len?k]+fj(i,i+len?1));f[i][len]=min(f[i][len],f[i][k]+f[(i+k-1)modn+1][len-k]+fj(i,i+len-1));f[i][len]=min(f[i][len],f[i][k]+f[(i+k?1)modn+1][len?k]+fj(i,i+len?1));
l[i][len]=max(l[i][len],l[i][k]+l[(i+k?1)modn+1][len?k]+fj(i,i+len?1));l[i][len]=max(l[i][len],l[i][k]+l[(i+k-1)modn+1][len-k]+fj(i,i+len-1));l[i][len]=max(l[i][len],l[i][k]+l[(i+k?1)modn+1][len?k]+fj(i,i+len?1));

注釋:

(i+k-1) mod n+1為什么不寫成(i+k)mod n呢?因為當i+k=n時,結果為0,0不在我們的計算范圍內,所以我們要用(i+k-1) mod n+1,用這種的話,當i+k=n時,結果為n。fj(i,i+len-1)為計算i到i+len-1之間的數

#include<cstdio> #include<iostream> using namespace std; int a[105],f[105][105],l[105][105],s[105],n,minn,maxx; int fj(int x,int y) {if (y<=n) return s[y]-s[x-1];//沒有超過nreturn fj(x,n)+fj(1,y-n);//分兩段 } int main() {memset(f,127/3,sizeof(f));scanf("%d",&n);for (int i=1;i<=n;i++){scanf("%d",&a[i]);s[i]=s[i-1]+a[i];f[i][1]=0;}for (int len=2;len<=n;len++)//長度for (int i=1;i<=n;i++)//前面的for (int k=1;k<len;k++)//分界線{f[i][len]=min(f[i][len],f[i][k]+f[(i+k-1)%n+1][len-k]+fj(i,i+len-1));//狀態轉移方程l[i][len]=max(l[i][len],l[i][k]+l[(i+k-1)%n+1][len-k]+fj(i,i+len-1));//狀態轉移方程}minn=2147483647;for (int i=1;i<=n;i++){minn=min(minn,f[i][n]);//求最小的maxx=max(maxx,l[i][n]);//求最大的}printf("%d\n%d",minn,maxx); } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的【动态规划】 石子合并问题(环形) (ssl 1597)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。