時間限制:
1000 ms | 記憶體限制:
65535 kb
難度:3 描述
有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n-1次合併後成為一堆。求出總的代價最小值。
輸入
有多組測試資料,輸入到檔案結束。
每組測試資料第一行有乙個整數n,表示有n堆石子。
接下來的一行有n(0< n <200)個數,分別表示這n堆石子的數目,用空格隔開
輸出輸出總代價的最小值,佔單獨的一行
樣例輸入
31 2 3
713 7 8 16 21 4 18
樣例輸出
9239
解題:dp...其實就是把這條直線先化成長度為1的一段一段一段的,然後化成長度為2的一段一段的。。。。。。。。最優子結構。。。。拼出0-n-1的最優解
我的**:
# include # include # define inf 100000000# define min(a,b)aint sum[210],add,n,i,j,v,k,dp[210][210],c[210];
while (~scanf("%d", &n))
for (v = 1; v < n; v++)
for (i = 1; i <= n - v; i++)
printf("%d\n", dp[1][n]);
}return 0;
}最優**:
思路:設序列是stone,從左往右,找乙個滿足stone[k-1] <= stone[k+1]的k,找到後合併stone[k]和stone[k-1],再從當前位置開始向左找最大的j,使其滿足stone[j] > stone[k]+stone[k-1],插到j的後面就行。一直重複,直到只剩下一堆石子就可以了。在這個過程中,可以假設stone[-1]和stone[n]是正無窮的。舉個例子:
186 64 35 32 103
因為35<103,所以最小的k是3,我們先把35和32刪除,得到他們的和67,並向前尋找乙個第乙個超過67的數,把67插入到他後面,得到:186 67 64 103,現在由5個數變為4個數了,繼續:186 131 103,現在k=2(別忘了,設a[-1]和a[n]等於正無窮大)234 186,最後得到420。最後的答案呢?就是各次合併的重量之和,即420+234+131+67=852。
基本思想是通過樹的最優性得到乙個節點間深度的約束,之後證明操作一次之後的解可以和原來的解一一對應,並保證節點移動之後他所在的深度不會改變。具體實現這個演算法需要一點技巧,精髓在於不停快速尋找最小的k,即維護乙個「2-遞減序列」樸素的實現的時間複雜度是o(n*n),但可以用乙個平衡樹來優化,使得最終複雜度為o(nlogn)。
**:
#include #include #include using namespace std;const int n = 50005;
int stone[n];
int n,t,ans;
void combine(int k)
}int main()
while(t > 1) combine(t-1);
printf("%d\n",ans);
}return 0;
}
石子合併(一)
時間限制 1000 ms 記憶體限制 65535 kb 難度 3 描述 有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。輸入 有多組測試資料,輸入到檔案...
石子合併(一)
時間限制 1000 ms 記憶體限制 65535 kb 難度 3 描述 有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。輸入 有多組測試資料,輸入到檔案...
石子合併(一)
時間限制 1000 ms 記憶體限制 65535 kb 難度 3 描述 有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。輸入 有多組測試資料,輸入到檔案...