演算法_動態規劃(最大子段和、0-1揹包、迴文串問題、矩陣鏈相乘問題、尋寶)
最大子段和
給定n個整數(可能為負數)組成的序列a[1],a[2],a[3],…,a[n],求該序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。當所給的整數均為負數時,定義子段和為0。
要求演算法的時間複雜度為O(n)。
輸入格式:
輸入有兩行:
第一行是n值(1<=n<=10000);
第二行是n個整數。
輸出格式:
輸出最大子段和。
輸入樣例:
在這裡給出一組輸入。例如:
6
-2 11 -4 13 -5 -2
輸出樣例:
在這裡給出相應的輸出。例如:
20
程式碼:
#include <iostream>
using namespace std;
int main()
{
int i,n, a[100], sum = 0, b = 0,start=0,end=0;
cin >> n;
for (i = 0; i < n; i++)
cin>>a[i] ;
for (i = 0; i < n; i++) {
if (b > 0){
if (start == 0)
start = i;
else
end = i;
b += a[i];
}
else b = a[i];
if (b > sum) sum = b;
}
cout << sum << endl;
return 0;
}
0-1揹包
給定n(n<=100)種物品和一個揹包。物品i的重量是wi,價值為vi,揹包的容量為C(C<=1000)。問:應如何選擇裝入揹包中的物品,使得裝入揹包中物品的總價值最大? 在選擇裝入揹包的物品時,對每種物品i只有兩個選擇:裝入或不裝入。不能將物品i裝入多次,也不能只裝入部分物品i。
輸入格式:
共有n+1行輸入: 第一行為n值和c值,表示n件物品和揹包容量c; 接下來的n行,每行有兩個資料,分別表示第i(1≤i≤n)件物品的重量和價值。
輸出格式:
輸出裝入揹包中物品的最大總價值。
輸入樣例:
在這裡給出一組輸入。例如:
5 10
2 6
2 3
6 5
5 4
4 6
輸出樣例:
在這裡給出相應的輸出。例如:
15
程式碼:
#include <iostream>
using namespace std;
int dp[105][1005] = { 0 };
int n, c;
int w[105], v[105];
void solve(){
for (int i = 0; i<n; i++){
for (int j = 0; j <= c; j++){
if (j<w[i]){
dp[i + 1][j] = dp[i][j];
}
else{
if (dp[i][j - w[i]] + v[i]>dp[i][j])
dp[i + 1][j] = dp[i][j - w[i]] + v[i];
else
dp[i + 1][j] = dp[i][j];
}
}
}
}
int main(){
cin >> n >> c;
for (int i = 0; i<n; i++){
cin >> w[i] >> v[i];
}
solve();
cout << dp[n][c] << endl;
return 0;
}
迴文串問題
一個字串,如果從左到右讀和從右到左讀是完全一樣的,比如"aba",我們稱其為迴文串。現在給你一個字串,可在任意位置新增字元,求最少新增幾個字元,才能使其變成一個迴文串。
輸入格式:
任意給定的一個字串,其長度不超過1000.
輸出格式:
能變成迴文串所需新增的最少字元數。
輸入樣例:
在這裡給出一組輸入。例如:
Ab3bd
Abb
輸出樣例:
在這裡給出相應的輸出。例如:
2
1
程式碼:
#include<iostream>
#include<cstring>
using namespace std;
int dp[1010][1010];
int main()
{
char s[1010];
int i, j, len;
cin >> s;
len = strlen(s);
memset(dp, 0, sizeof(dp));
for (i = 0; i < len; i++)
for (j = 0; j<len; j++)
{
if (s[i] == s[len - 1 - j])
dp[i + 1][j + 1] = dp[i][j] + 1;
else{
if (dp[i][j + 1]>dp[i + 1][j])
dp[i + 1][j + 1] = dp[i][j + 1];
else
dp[i + 1][j + 1] = dp[i + 1][j];
}
}
cout << len - dp[len][len] << endl;
}
矩陣鏈相乘問題
輸入格式:
每個輸入檔案為一個測試用例,每個測試用例的第一行給出一個正整數n(1≤n≤100),表示一共有n個矩陣A1 ,A2 ,…,An ,第二行給出n+1個整數P0 ,P1 …Pn ,以空格分隔,其中1≤Pi ≤100(0≤i≤n),第i個矩陣Ai 是階為Pi−1 ∗Pi 的矩陣。
輸出格式:
獲得上述矩陣的乘積,所需的最少乘法次數。
輸入樣例:
在這裡給出一組輸入。例如:
5
30 35 15 5 10 20
輸出樣例:
在這裡給出相應的輸出。例如:
11875
程式碼:
#include <iostream>
#include <climits>
using namespace std;
int p[1010], dp[1010][1010];
int res(int n){
for (int k = 2; k <= n; k++){
for (int i = 1; i <= n + 1 - k; i++){
int j = i + k - 1;
dp[i][j] = INT_MAX;
for (int m = i; m<j; m++){
if (dp[i][j]< dp[i][m] + dp[m + 1][j] + p[i - 1] * p[m] * p[j])
dp[i][j] = dp[i][j];
else
dp[i][j] = dp[i][m] +dp[m + 1][j] + p[i - 1] * p[m] * p[j];
}
}
}
return dp[1][n];
}
int main() {
int n;
cin >> n;
for (int i = 0; i <= n; i++){
cin >> p[i];
}
cout << res(n) << endl;
return 0;
}
尋寶
小明有一張藏寶圖,上面有m*n個房間,每個房間裡面都有一個有一定價值的寶物,小明只能從左上角的房間進入收集寶物,且每次只能向右邊或向下邊的房間繼續尋寶,最終只能從最右下的房間出來。請你幫小明計算下他最多可以收集到多少價值的寶物?
輸入格式:
輸入第一行給出兩個正整數m,n(1=<m,n<=2000),隨後給出m行資料,每行都包括n個正整數,中間用空格分割。
輸出格式:
輸出收集到的最大價值v,題目保證v<10^9。
輸入樣例:
4 4
1 18 9 3
7 10 6 12
5 13 4 15
2 11 8 16
輸出樣例:
78
程式碼:
#include <iostream>
#include <algorithm>
using namespace std;
int a[2010][2010],dp[3][2010];
int main() {
int x, y;
cin >> x>>y;
for (int i = 1; i <= x; i++)
for (int j = 1; j <= y; j++)
cin >> a[i][j];
for (int i = 1; i <= x; i++){
for (int j = 1; j <= y; j++){
dp[i % 2][j] = max(dp[(i - 1) % 2][j], dp[i % 2][j - 1]) + a[i][j];
}
}
cout << dp[x % 2][y] << endl;
return 0;
}