1. 程式人生 > 其它 >演算法_動態規劃(最大子段和、0-1揹包、迴文串問題、矩陣鏈相乘問題、尋寶)

演算法_動態規劃(最大子段和、0-1揹包、迴文串問題、矩陣鏈相乘問題、尋寶)

技術標籤:PTA演算法

最大子段和

給定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個矩陣A​1​​ ,A​2​​ ,…,A​n​​ ,第二行給出n+1個整數P​0​​ ,P​1​​ …P​n​​ ,以空格分隔,其中1≤P​i​​ ≤100(0≤i≤n),第i個矩陣A​i​​ 是階為P​i−1​​ ∗P​i​​ 的矩陣。

輸出格式:
獲得上述矩陣的乘積,所需的最少乘法次數。

輸入樣例:
在這裡給出一組輸入。例如:

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;
}

在這裡插入圖片描述