动态规划

DP

  • 一个具有重叠子问题和最优子结构的问题,才可以使用动态规划
  • 状态的无后效性:即已有的状态不会随着后面转变

避免重复计算

斐波那契数列

//斐波那契数列
//F0=1,F1=1,Fn=Fn-1+Fn-2
#include<algorithm>
using namespace std;
const int max_n = 100;
int f[max_n];
int Fib(int n)
{
	if (f[n] != -1)
	{
		return f[n];
	}
	else
	{
		f[n] = Fib(n - 1) + Fib(n - 2);
	}
	return f[n];
}
int main()
{
	fill(f, f + max_n, -1);
	f[0] = 1;
	f[1] = 0;
}

数塔

//树塔问题 第n层有n个数 求某一条路径上的最大值
//max[i]表示从i出发 某条路径和的最大值
#include<stdio.h>
const int max_n = 30;
int n,k;//假设有k层 n个结点
struct node
{
	int w;
	int left;
	int right;
}Adj[max_n];
int max[max_n];
int main()
{
	for (int i = n-1-k; i<n; i++)
	{
			max[i] = Adj[i].w;
	}
	for (int i = n - 2 - k; i>=0; i--)
	{
		if (max[Adj[i].left] > max[Adj[i].right])
		{
			max[i] = Adj[i].w + max[Adj[i].left];
		}
		else
		{
			max[i] = Adj[i].w + max[Adj[i].right];
		}
	
	}
}

最大连续子序列和

//最大连续子序列和
//给定一个数组 求出其最大连续子序列的和
const int max_n = 30;
int n;
int dp[max_n];//dp表示以i结尾的最大连续子序列的和
int w[max_n];
int max;
int main()
{
	dp[0] = w[0];
	max = dp[0];
	for (int i = 1; i < n; i++)
	{
		if (w[i] > dp[i - 1] + w[i])
		{
			dp[i] = w[i];
			
		}
		else
		{
			dp[i] = w[i] + dp[i - 1];
		}
		if (dp[i] > max)
		{
			max = dp[i];
		}
	}
}

最长不减子序列

#include<iostream>
#include<stack>
using namespace std;
//在一个数组中 找到一组不下降的子序列
const int max_n = 100;

int main()
{
	int n;
	int dp[max_n];//记录以第i个元素结尾的序列最大长度
	int max_pre[max_n];//记录第i个元素的前一个元素
	int A[max_n];
	int maxIndex = 0;//记录拥有最大不下降子序列的结尾
	stack<int>s;
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &A[i]);
	}
	fill(max_pre, max_pre + n, -1);
	dp[0] = 1;
	for (int i = 1; i < n; i++)
	{
		dp[i] = 1;
		for (int j = 0; j <=i - 1; j++)
		{
			if (A[i] >= A[j] && dp[j] + 1 > dp[i])
			{
				dp[i] = dp[j] + 1;
				max_pre[i] = j;
			}
		}
		if (dp[maxIndex] < dp[i])
		{
			maxIndex = i;
		}
	}
	
	int index = maxIndex;
	while (max_pre[index]!=-1)
	{
		s.push(index);
		index = max_pre[index];
	}
	s.push(index);
	printf("%d\n",s.size());
	while (!s.empty())
	{
		int f = s.top();
		s.pop();
		printf("%d ", A[f]);
	}
}

最长公共子序列

题目描述

  • 有两个字符串A和B,求一个字符串,这个字符串是A和B的公共子序列

代码

//最长公共子序列
#include<string>;
#include<algorithm>
#include<iostream>
#include<stack>
using namespace std;
//最长公共子序列
const int max_n = 300;
int alen, blen;
int dp[max_n][max_n];//表示Ai和Bj之间的最长公共子序列
int prex[max_n][max_n];
int prey[max_n][max_n];
string A, B;
stack<char> s;
int main()
{
	for (int i = 0; i < max_n; i++)
	{
		for (int j = 0; j < max_n; j++)
		{
			prex[i][j] = -1;
			prey[i][j] = -1;
		}
	}
	cin >> A;
	cin >> B;
	alen = A.length();
	blen = B.length();

	dp[0][0] = A[0] != B[0] ? 0 : 1;
	for (int j = 0; j < blen; j++)
	{
		dp[0][j]= A[0] != B[j] ? 0 : 1;
	}
	int res = 0;
	int x = 0, y = 0;
	for (int j = 0; j < alen; j++)
	{
		dp[j][0] = A[j] != B[0] ? 0 : 1;
	}
	for (int i = 1; i < alen; i++)
	{
		for (int j = 1; j < blen; j++)
		{
			if (A[i] == B[j])
			{
				dp[i][j] = dp[i - 1][j - 1] + 1;
				prex[i][j] = i - 1;
				prey[i][j] = j - 1;
			}
			else
			{
				if (dp[i - 1][j] > dp[i][j - 1])
				{
					dp[i][j] = dp[i - 1][j];
					prex[i][j] = i - 1;
					prex[i][j] = j;
				}
				else
				{
					dp[i][j] = dp[i][j-1];
					prex[i][j] = i;
					prex[i][j] = j-1;
				}
			}
			if (res < dp[i][j])
			{
				res = dp[i][j];
				x = i;
				y = j;
			}
		}
	}
	
	printf("%d\n",res);
	while (x!=-1)
	{
		s.push(A[x]);
		int a = x, b = y;
		x = prex[a][b];
		y = prey[a][b];
	}
	for (int i = 0; i < res; i++)
	{
		int v = s.top();
		s.pop();
		printf("%c ", v);
	}
}

最长回文子串

//最长回文子串
#include<iostream>
using namespace std;
const int max_n = 300;
int n;
int maxL=1, maxX=0, maxY=0;
bool dp[max_n][max_n];
string s;
int main()
{
	cin >> s;
	n = s.length();
	//初始化
	for (int i = 0; i < n; i++)
	{
		dp[i][i] = true;
	}
	for (int i = 0; i < n-1; i++)
	{
		dp[i][i + 1] = s[i] == s[i + 1];
	}
	for (int L = 3; L <= n; L++)
	{
		for (int i = 0; i < n+1-L; i++)
		{
			int end = i + L - 1;
			dp[i][end] = false;
			if (s[i] == s[end])
				dp[i][end] = dp[i + 1][end - 1];
		}
	}
	for (int i = 0; i < n; i++)
	{
		for (int j = i; j < n; j++)
		{
			if (dp[i][j])
			{
				int tL = j - i + 1;
				if (tL > maxL)
				{
					maxL = tL;
					maxX = i;
					maxY = j;
				}
			}
			
		}
	}
	printf("%d\n", maxL);
	for (int i = maxX; i <= maxY; i++)
	{
		printf("%c", s[i]);
	}
}

DAG最长路

//DAG最长路
#include<iostream>
#include<algorithm>
using namespace std;
const int max_n = 300;
const int INF = 0x3fffffff;
int n;
int G[max_n][max_n];
bool dp[max_n];//表示从i出发的最长路径
int nextNode[max_n];//记录i的后继结点
int DP(int x)
{
	if (dp[x] != 0)return dp[x];
	for (int i = 0; i < n; i++)
	{
		if (G[x][i]!=INF)
		{
			int temp = DP(i) + G[x][i];
			if (temp > dp[x])
			{
				dp[x] = temp;
				nextNode[x] = i;
			}
		}
	}
	return dp[x];
}
int main()
{
        fill(dp,dp+n,0);
	fill(nextNode, nextNode + n, -1);
	int maxIndex = 0;
	for (int i = 0; i < n; i++)
	{
		if (dp[i] > dp[maxIndex])
		{
			maxIndex = i;
		}
	}
	printf("%d", dp[maxIndex]);
	int index = maxIndex;
	while (nextNode[index] != -1)
	{
		printf("%d ", index);
		index = nextNode[index];
	}
	
}
posted @ 2021-09-09 21:39  小帆敲代码  阅读(29)  评论(0编辑  收藏  举报