zoukankan      html  css  js  c++  java
  • 动态规划

    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
    ",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
    ",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
    ", 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];
    	}
    	
    }
    
  • 相关阅读:
    rmq +二分暴力 hdu 5726
    8.25 ccpc 比赛总结
    莫比乌斯反演题目总结
    HDU 4848 Wow! Such Conquering! (搜索+floyd)
    Codeforces 982 C Cut 'em all!(DFS)
    Codefoces 986C AND Graph(DFS)
    CodeForces 986A Fair(BFS)
    ACM经验贴
    Kattis A+B Problem(FFT)
    CF E. Porcelain (双向dp)
  • 原文地址:https://www.cnblogs.com/code-fun/p/15245451.html
Copyright © 2011-2022 走看看