dp 订阅
DisplayPort(简称DP)是一个由PC及芯片制造商联盟开发,视频电子标准协会(VESA)标准化的数字式视频接口标准。该接口免认证、免授权金,主要用于视频源与显示器等设备的连接,并也支持携带音频、USB和其他形式的数据。此接口的设计是为取代传统的VGA、DVI和FPD-Link(LVDS)接口。通过主动或被动适配器,该接口可与传统接口(如HDMI和DVI)向后兼容。 展开全文
DisplayPort(简称DP)是一个由PC及芯片制造商联盟开发,视频电子标准协会(VESA)标准化的数字式视频接口标准。该接口免认证、免授权金,主要用于视频源与显示器等设备的连接,并也支持携带音频、USB和其他形式的数据。此接口的设计是为取代传统的VGA、DVI和FPD-Link(LVDS)接口。通过主动或被动适配器,该接口可与传统接口(如HDMI和DVI)向后兼容。
信息
定    义
数字式视频接口标准
简    称
DP
开发者
PC及芯片制造商联盟
中文名
显示接口
学    科
通讯工程
外文名
DisplayPort
DisplayPort接口概观
DisplayPort是第一个依赖数据包化数据传输技术的显示通信端口,这种数据包化传输技术可以在以太网、USB和PCI Express等技术中找到。它既可以用于内部显示连接,也可以用于外部的显示连接。与过去的标准需要在每个输出端的差分对里面固定传输定时器信号不同的是,DisplayPort协议是基于小的数据报文被称为微报文,这种微报文可以将定时器信号嵌入在数据流中。其优点是较少的引脚数,就可以实现更高的分辨率。数据报文的应用也允许使用DisplayPort可扩展,这就意味着随着时间的推移,物理通信端口本身不需要显著的变化就可以增加额外的功能了。 [1]  DisplayPort可用于同时传输音频和视频,这两项中每一项都可以在没有另外一项的基础上单独传输。视频信号路径中每个颜色通道可以有6到16位,音频路径可以有多达8通道24位192 kHz的非压缩的PCM音频,或可以在音频流中封装压缩的音频格式。一个双向的、半双工的辅助通道携带了主链接用的设备管理和设备控制数据,如VESAEDID、MCCS和DPMS标准。此外,该通信端口是能够运送双向USB信号。DisplayPort信号不兼容DVI或HDMI。然而,双模式DisplayPorts被设计用来通过该通信端口传输单链接DVI或HDMI1.2/1.4的协议,需要通过使用一个外部无源连接器来实现,选择所需的信号,并将电气信号从LVDS转换为TMDS。带有被动连接器的双模DisplayPorts不支持VGA和双链接DVI。这些通信端口需要有源连接器来转换所需要输出的协议和信号。VGA连接器可以使用DisplayPort连接器来供电,而双链接DVI连接器可能依赖于外部电源(参考HDMI、DVI和VGA兼容性)。DisplayPort连接器在主链路可以有1、2、或4路差分数据对(巷道),每巷道可以在自定时器运行于162、270、或540MHz的基础上其原始码率为1.62、2.7或者5.4 Gbit/s。数据为8b/10b编码,即每8位的消息被编入10比特符号中。因此,解码后每通道的有效数据传输速率是1.296、2.16、4.32 Gbit/s(或者说是总量的80%)。
收起全文
精华内容
下载资源
问答
  • 动态规划(DP)

    千次阅读 多人点赞 2020-04-15 23:33:23
    DP

    动态规划(DP)
    用来优化加速,时间复杂度从指数(Exponential) 加速到多项式时间(Polynomial)。
    何时使用DP?

    • 计数问题:求有多少种方法
    • 优化问题:max和mim问题

    使用DP的要求

    • 最优子结构:
    • 重复子问题:求解子问题时,会出现重复计算(overlapping)。如果没有重复计算,则退化成分治算法(divide and conquer)
    • 无后效性:调用子问题最优解时,子问题的最优解不发生改变。

    使用方法

    1. 带有记忆性的递归
      举例:斐波那契序列
    2. DP

    典型题目

    斐波那契序列

    分析
    递推公式和边界条件已知。存在重复计算的问题,类似带有记忆性的递归,即使用数组保存先前的结果,减少重复计算。

    开一个数组dp[]
    for i in range(3,n)
    dp[i]=dp[i-1]+dp[i-2]
    仅需一个for loop

    代码

    int DP(int n)
    {
    	int dp[n+1];
    	dp[1]=1;dp[2]=1;
    	for(int i=3;i<=n;i++)
    		dp[i]=dp[i-1]+dp[i-2];
    	return dp[n];
    }
    

    三角形数

    题目
    给定一个由行数字组成的数字三角形。试着设计一个算法,计算出从三角形的顶到底的一条路径,使得该路径经过的数字总和最大。
    测试数据

    1
    2 3
    20 5 6
    7 8 9 10
    最大值 31

    思路1:
    自底向上方向,MaxSum[ i ] [ j ]表示第i行第j列的数到最底下路径和的最大值。
    MaxSum[ i] [ j] 和MaxSum[ i ][ j+1]中的较大者,作为第i-1行的转移项。
    代码

    #include<iostream>
    
    using namespace std;
    
    const int maxn=1e2+2;
    
    int D[maxn][maxn],MaxSum[maxn][maxn]; 
    int main()
    {
    	int i,j;
    	int N;
    	cin>>N;//输入N行测试数据
    	for(i=1;i<=N;i++)
    		for(j=1;j<=i;j++) 
    			cin>>D[i][j];
    
    	for(i=1;i<=N;i++)//最大权值和初始化为最后一列 
    		MaxSum[N][i]=D[N][i];
    		
    	for(i=N;i>1;i--)
    		for(j=1;j<i;j++)
    		{
    			if(MaxSum[i][j]>MaxSum[i][j+1])//比较左右两边数据大小 
    				MaxSum[i-1][j]=D[i-1][j]+MaxSum[i][j];//更新上一行最大权值的和 
    			else
    				MaxSum[i-1][j]=D[i-1][j]+MaxSum[i][j+1];
    		}
    	//最大值在MaxSum[1][1]
    	cout<<MaxSum[1][1]<<endl;	
    } 
    

    需要注意
    注意数组的边界,数组不是从0开始,这里使用从1开始。
    对于第i行,需要使用第i+1行的数据,对于for(i=N;i>1;i–)这里

    思路2:自上到下,思路在下方代码上面。

    下面这道题目可能包含负数。

    Acwing898. 数字三角形

    输入格式
    第一行包含整数n,表示数字三角形的层数。

    接下来n行,每行包含若干整数,其中第 i 行表示数字三角形第 i 层包含的整数。

    输出格式
    输出一个整数,表示最大的路径数字和。

    数据范围
    1≤n≤500,
    −10000≤三角形中的整数≤10000
    输入样例:
    5
    7
    3 8
    8 1 0
    2 7 4 4
    4 5 2 6 5
    输出样例:
    30

    
    /*
    
    数字三角形思路分析;
    
    状态表示f[i,j]
        集合:所有从起点到(i,j)的路径
        属性:max
    
    状态计算
    f[i,j]可以来自左上和右上两种情况:
        左上:f[i-1][j-1]+a[i][j]
        右上:f[i-1][j]+a[i][j]
    
    */
    
    
    /*
        dp问题的时间复杂度分析:  状态数量 × 转移的计算量
        
        本题:状态数量n^2 ,转移计算量O(1),所以本题时间复杂度O(n^2)
    */
    
    #include<bits/stdc++.h>
    using namespace std;
    const int N=510,INF=1e9;
    int n;
    int f[N][N];
    
    int a[N][N];
    
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i;j++)
                cin>>a[i][j];
        }
        
        //初始化多初始化两侧两列:因为计算 f[i][1]需要用到f[i-1][0],这里第0列需要初始化
         for(int i=1;i<=n;i++){
            for(int j=0;j<=i+1;j++)
                f[i][j]=-INF;
        }
        int res=-INF;
        
        f[1][1]=a[1][1];
        
        for(int i=2;i<=n;i++){
            for(int j=1;j<=i;j++)
            {
                    f[i][j]= max(f[i-1][j-1]+a[i][j],f[i-1][j]+a[i][j]);
            }
                 
        }
        //结果在最后一行取
        for(int i=1;i<=n;i++) res=max(res,f[n][i]);
        cout<<res<<endl;
        
        
        
        
        
    }
    
    

    最小路径和

    Leetcode 64
    题目
    给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
    说明:每次只能向下或者向右移动一步。

    示例:

    输入:
    [
    [1,3,1],
    [1,5,1],
    [4,2,1]
    ]
    输出: 7
    解释: 因为路径 1→3→1→1→1 的总和最小。

    ac代码

    class Solution {
    public:
        int minPathSum(vector<vector<int>>& grid) {
            int m=grid.size();
            int n=grid[0].size();
            vector<vector<int>> f(m,vector<int>(n,0));//m*n的两维vector,全0
            //状态
             f[0][0]=grid[0][0];
            for(int i=1;i<n;i++)//第一行
                f[0][i]+=grid[0][i]+f[0][i-1];
                
            f[0][0]=grid[0][0];
            for(int i=1;i<m;i++)//第一列
                f[i][0]+=grid[i][0]+f[i-1][0];
            //转移
            for(int i=1;i<m;i++)
                for(int j=1;j<n;j++)
                     f[i][j]=grid[i][j]+min(f[i-1][j],f[i][j-1]);            
            return f[m-1][n-1];
    
        }
    };
    

    最长上升子序列(LIS)

    题目链接:Acwing895. 最长上升子序列
    问题描述
    一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8)。你的任务,就是对于给定的序列,求出最长上升子序列的长度。
    输入数据
    输入的第一行是序列的长度N(1<=N<=1000)。第二行给出的序列中的N个整数,这些整数的取值范围都是0-10000。
    输出要求
    最长上升子序列的长度。

    输入样例
    7
    1 7 3 5 9 4 8
    输出样例
    4

    分析
    求 a1_1,a2_2,…,ak_k,…,an_n 的最长上升子序列
    子问题是求 a1_1,a2_2,…,ak_k的最长上升子序列

    dp[i]表示终点是ai_i 的最长上升子序列的长度
    动态规划

    1. 状态转移 : dp[ i ] = max { dp[ j ]+1 , dp[ i ] } , 对于所有的 j< i ,并且 fj_j<fi_i
      含义: 以aj_j为终点的最长子序列长度加上 ai_i本身 就是 以 ai_i结尾的最长子序列的长度, 即 dp[ j ]+1
    2. base cases :dp[ i ] =1 ,i ∈ [0,n)
      含义:初始时每个位置的最长上升子序列长度都为1,即它本身

    时间复杂度 O(n2^2)

    代码

    #include<iostream>
    using namespace std;
    
    const int maxn=1010;
    int f[maxn],dp[maxn];
    //dp[i]表示终点是i的最长上升子序列的长度 
    int ans=1;//保存结果 
    int main()
    {
    	int N;
    	cin>>N;
    	for(int i=1;i<=N;i++)
    	{
    		cin>>f[i];
    		dp[i]=1;//边界处理 
    	}
    
    	//转移 
    	for(int i=1;i<=N;i++)
    	{
    		for(int j=1;j<i;j++)
    		{
    			if(f[j]<f[i]) dp[i]=max(dp[i],dp[j]+1);
    		}		
    		ans=max(ans,dp[i]);
    	}
    	cout<<ans;		
    } 
    

    补充最长下降子序列(LDS)和最长上升子序列(LIS)分装成函数:

    #include<iostream>
    
    using namespace std;
    const int maxn=1010;
    
    long long a[maxn],dp[maxn];
    
    //最长下降子序列 
    long long LDS( long long a[],int N)
    {
    	long long  temp=0;
    	for(int i=1;i<=N;i++)
    	 dp[i]=1;
    	 for(int i=1;i<=N;i++)
    	 {
    	 	for(int j=1;j<i;j++)
    	 	{
    	 		if(a[j]>a[i])
    	 			dp[i]=max(dp[j]+1,dp[i]);
    	 	}
    	 	temp=max(dp[i],temp);
    	 }
    	 
    	 return temp;
    }
    //最长上升子序列 
    long long LIS( long long a[],int N)
    {
    	long long  temp=0;
    	for(int i=1;i<=N;i++)
    	 dp[i]=1;
    	 for(int i=1;i<=N;i++)
    	 {
    	 	for(int j=1;j<i;j++)
    	 	{
    	 		if(a[j]<a[i])
    	 			dp[i]=max(dp[j]+1,dp[i]);
    	 	}
    	 	temp=max(dp[i],temp);
    	 }
    	 
    	 return temp;
    }
    
    int main()
    {
    	
    	int N;
    	cin>>N;
    	for(int i=1;i<=N;i++) 
    		{
    			cin>>a[i];
    		}
    	cout<<LDS(a,N)<<endl;
    	cout<<LIS(a,N)<<endl; 
    }
    

    最长公共子序列

    Leetcode1143. 最长公共子序列
    问题描述
    输入两个字符串, 要你求出两个字符串的最长公共子序列长度。
    输入
    输入两行不超过200的字符串。
    输出
    给出两个字符串的最大公共字符串的长度。

    样例输入
    abcfbc
    abfcab
    样例输出
    4

    分析
    状态转移
    我们需要看字符串 s1 第i个字母 和 字符串 s2 第j个字母的关系
    if s1i_i == s2j_j
    同时去掉各自最后的字母,看s1i_i-1_1 和 s2j_j-1_1
    得到 dp[ i ] [ j ] = dp [ i-1 ] [ j -1 ]+1

    if s1i_i != s2j_j
    若去掉 s1i_i ,看 s1i_i-1_1 和 s2j_j 的公共子序列 与
    若去掉 s2j_j,看s1i_i和 s2j_j-1_1的公共子序列
    取两者最大值 dp[ i ] [ j ] = max (dp [ i ] [ j-1 ],dp [ i-1] [ j ] );

    时间复杂度O(m×n)O(m \times n),两个字符串的长度。

    代码

    class Solution {
    public:
        int longestCommonSubsequence(string text1, string text2) {
            int m=text1.size();
            int n=text2.size();
            int dp[m+1][n+1];
            
           memset(dp,0,sizeof(dp));//置零
            for(int i=1;i<=m;i++)
                for(int j=1;j<=n;j++)
                {
                    if(text1[i-1]!=text2[j-1])
                    dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
    
                    if(text1[i-1]==text2[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                }
            return dp[m][n]; 
        }
    };
    

    板子题目链接:Acwing897. 最长公共子序列

    ac代码

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1000;
    int n,m;
    int dp[N+1][N+1];
    int main(){
        string t1,t2;
        cin>>n>>m;
        cin>>t1>>t2;
       
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(t1[i-1]==t2[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else{
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                }
            }
            
        }
        cout<<dp[n][m]<<endl;
        
    }
    

    将字符串翻转成单增

    Leetcode 926
    如果一个由 ‘0’ 和 ‘1’ 组成的字符串,是以一些 ‘0’(可能没有 ‘0’)后面跟着一些 ‘1’(也可能没有 ‘1’)的形式组成的,那么该字符串是单调递增的。

    我们给出一个由字符 ‘0’ 和 ‘1’ 组成的字符串 S,我们可以将任何 ‘0’ 翻转为 ‘1’ 或者将 ‘1’ 翻转为 ‘0’。

    返回使 S 单调递增的最小翻转次数。

    示例 1:
    输入:“00110”
    输出:1
    解释:我们翻转最后一位得到 00111.
    示例 2:
    输入:“010110”
    输出:2
    解释:我们翻转得到 011111,或者是 000111。
    示例 3:
    输入:“00011000”
    输出:2
    解释:我们翻转得到 00000000。
    提示:
    1 <= S.length <= 20000
    S 中只包含字符 ‘0’ 和 ‘1’

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/flip-string-to-monotone-increasing

    分析
    求最长不降子序列(LIS),字符串长度减去LIS 即可
    使用 DP算法求解LIS超时。

    超时代码(思路是对的)
    时间复杂度O(n2n^2)

    class Solution {
    public:
        int minFlipsMonoIncr(string S) {
            int len=S.size();
            int dp[len+1];
            for(int i=0;i<=len;i++)
                dp[i]=1;
             int ans=0;
            for(int i=0;i<len;i++)
            {
                for(int j=0;j<i;j++)
                {
                    if(S[j]<=S[i])
                    dp[i]=max(dp[i],dp[j]+1);
                }
                ans=max(dp[i],ans);
            }
            return len-ans;
        }
         
    };
    

    优化代码(AC)
    维护单调数列,使用二分法。

    采用upper_bound()函数,返回第一个大于x的位置这样的话,遇到相等的元素,则一直会添加到数组中来
    时间复杂度O(nlogn)
    空间复杂度O(n)

    class Solution {
    public:
        int minFlipsMonoIncr(string S) {
            int len=S.size();
            vector<char> vec;
            for(int i=0;i<len;i++)
            {
                //p是大于S[i]的下标
                int p = upper_bound(vec.begin(),vec.end(),S[i])-vec.begin();
                if(vec.size()==p) //新来的是最大的
                    vec.push_back(S[i]);//加入数组
                else//新来的比原位置的小
                    vec[p]=S[i];替换掉
            }
           return len-vec.size();//返回字符串长度-LIS
        }
         
    };
    
    
    

    迷雾森林

    补充一道简单的dp题

    链接:迷雾森林
    来源:牛客网

    赛时提示:保证出发点和终点都是空地

    帕秋莉掌握了一种木属性魔法
    这种魔法可以生成一片森林(类似于迷阵),但一次实验时,帕秋莉不小心将自己困入了森林
    帕秋莉处于地图的左下角,出口在地图右上角,她只能够向上或者向右行走

    现在给你森林的地图,保证可以到达出口,请问有多少种不同的方案

    答案对2333取模

    输入描述:
    第一行两个整数m , n表示森林是m行n列
    接下来m行,每行n个数,描述了地图
    0 - 空地
    1 - 树(无法通过)
    输出描述:
    一个整数表示答案
    此题需要在计算过程中%2333,同时在处理边界的时候,出现1的话后面的都不能通过;这里处理是多用了一行的一个格,省掉了一行和一列的边界处理。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=3010;
    
    int a[maxn][maxn];
    int n,m;
    long long  dp[maxn][maxn];
    
    
    template<class T>inline void read(T &res)
    {
    	char c;T flag=1;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    }
    
    
    int main(){
    	cin>>m>>n;
    	for(int i=1;i<=m;i++){
    		for(int j=1;j<=n;j++)
    			read(a[i][j]);
    	}
    	memset(dp,0,sizeof(dp));
    	dp[m+1][1]=1;
    	
    	for(int i=m;i>=1;i--){
    		for(int j=1;j<=n;j++){
    			if(a[i][j]!=1)
    			dp[i][j]=(dp[i+1][j]+dp[i][j-1])%2333;
    		}
    	}
    	
    		cout<<dp[1][n]<<endl;
    //	cout<<endl;
    //	for(int i=1;i<=m;i++){
    //		for(int j=1;j<=n;j++)
    //			cout<<dp[i][j]<<" ";
    //		cout<<endl; 
    //	}
    	
    	
    
    	
    	
    }
    
    /*
    3 5
    0 1 0 0 0
    0 0 0 0 0
    0 0 1 0 0
    
    
    */
    
    展开全文
  • 小 x 对数位 dp 很感兴趣,现在他在解决一道题目,要求求解出[x,y]闭区间内所有满足以下性质的数字个数: 相邻位数字差值的绝对值不能超过 7。 且最低位与最高位差值的绝对值要大于 2。 现在,给出 x=13930,y=...

    Description

    小 x 对数位 dp 很感兴趣,现在他在解决一道题目,要求求解出[x,y]闭区间内所有满足以下性质的数字个数:

    1. 相邻位数字差值的绝对值不能超过 7。
    2. 且最低位与最高位差值的绝对值要大于 2。
      现在,给出 x=13930,y=457439。请你告诉小 x,满足要求的数字个数。

    思路分析

    x和y都不是很大,直接暴力搜索就行。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int solve(int x) {
    	int a[6];
    	int ind = 0;
    	while(x) {
    		int j = x % 10;
    		x /= 10;
    		a[ind++] = j;
    	}
    	if(abs(a[ind - 1] - a[0]) <= 2) {
    		return 0;
    	}
    	for(int i = 1; i < ind; i++) {
    		if(abs(a[i] - a[i - 1]) > 7) {
    			return 0;
    		}
    	}
    	return 1;
    }
    
    int main() {
    	int res = 0;
    	for(int i = 13930; i <= 457439; i++) {
    		if(solve(i)) {
    			res++;
    		}
    	}
    	cout << res;
    	return 0;
    }
    
    展开全文
  • 安卓dp转px,px转dp方法

    万次阅读 2018-06-06 15:35:04
    dp转px: /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().densit...

    dp转px:

        /**
         * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
         */
        public static int dip2px(Context context, float dpValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dpValue * scale + 0.5f);
        }

    px转dp:

        /**
         * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
         */
        public static int px2dip(Context context, float pxValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (pxValue / scale + 0.5f);
        }

    转自:https://blog.csdn.net/Keep_Driving_XinYang/article/details/50498628

     

          最后推荐给一些想进大厂或者还没有拿到心仪offer的攻城狮们一本书,由大厂java面试官胡书敏编写,满满的干货,助你进到想去的公司。

     

    博主上传资源下载链接:

    自制免费无广告小说阅读APP下载:

    https://download.csdn.net/download/yonghuming_jesse/10390364

    全屏播放视频不拉伸源码:

    https://download.csdn.net/download/yonghuming_jesse/10646274

    科大讯飞语音评测服务接入源码:

    https://download.csdn.net/download/yonghuming_jesse/10616924

    android饺子播放器使用源码:

    https://download.csdn.net/download/yonghuming_jesse/10619119

    视频播放前显示视频第一帧源码:

    https://download.csdn.net/download/yonghuming_jesse/10646332

    展开全文
  • 区间dp入门

    万次阅读 多人点赞 2018-05-03 18:07:49
    什么是区间dp?顾名思义:区间dp就是在区间上进行动态规划,求解一段区间上的最优解。主要是通过合并小区间的 最优解进而得出整个大区间上最优解的dp算法。二.核心思路既然让我求解在一个区间上的最优解,那么我把这...

    一.什么是区间dp?

    顾名思义:区间dp就是在区间上进行动态规划,求解一段区间上的最优解。主要是通过合并小区间的 最优解进而得出整个大区间上最优解的dp算法。

    二.核心思路

    既然让我求解在一个区间上的最优解,那么我把这个区间分割成一个个小区间,求解每个小区间的最优解,再合并小区间得到大区间即可。所以在代码实现上,我可以枚举区间长度len为每次分割成的小区间长度(由短到长不断合并),内层枚举该长度下可以的起点,自然终点也就明了了。然后在这个起点终点之间枚举分割点,求解这段小区间在某个分割点下的最优解。

    板子:

    for(int len = 1;len<=n;len++){//枚举长度
            for(int j = 1;j+len<=n+1;j++){//枚举起点,ends<=n
                int ends = j+len - 1;
                for(int i = j;i<ends;i++){//枚举分割点,更新小区间最优解
                    dp[j][ends] = min(dp[j][ends],dp[j][i]+dp[i+1][ends]+something);
                }
            }
        }

    三.朴素区间dp(n^3)

    例题:石子归并1

    传送门:戳我呀

    转移方程:

    dp[j][ends] = min(dp[j][ends],dp[j][i]+dp[i+1][ends]+weigth[i][ends]);

    j~ends堆合并 = 较小的(原来, 分割点i坐部分重量 + 分割点i右边部分重量 + 合并后两堆总重量)

    注:可以用sum[j] - sum[i - 1]表示i~j堆的重量!

    代码:

    #include <iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define INF 0x3f3f3f
    int stone[105];
    int dp[105][105];
    int sum[105];
    int main()
    {
        int n;
        scanf("%d",&n);
        memset(sum,0,sizeof(sum));
        memset(dp,INF,sizeof(dp));
        for(int  i =1;i<=n;i++){
            scanf("%d",&stone[i]);
            sum[i] = sum[i - 1] + stone[i];//重量
            dp[i][i] = 0;
        }
        for(int len = 1;len<=n;len++){//枚举长度
            for(int j = 1;j+len<=n+1;j++){//枚举起点,ends<=n
                int ends = j+len - 1;
                for(int i = j;i<ends;i++){//枚举分割点
                    dp[j][ends] = min(dp[j][ends],dp[j][i]+dp[i+1][ends]+sum[ends]-sum[j-1]);//更新状态
                }
            }
        }
        cout<<dp[1][n]<<endl;
        return 0;
    }
    

    四.题目变形(线性变环状)

    例题:石子归并2

    题意:原题与上面相同,但是石子排列由线性排列变成环状排列,求解

    思路:环状以后合并区间的情况就可以从后往前合并,最后合并完成可能是1~n,2~n~1,3~n~2.....这种n个石子合并的情况。所以我们可以破环成链,将前n-1各元素也放到n后面构成一个线性的环状序列,在对这个序列dp即可

                                        

     

    代码:codevs 2102环状石子归并求最大值和最小值

    #include <iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define INF 0x3f3f3f
    int stone[105];
    int dpmin[205][205];//最小
    int dpmax[205][205];//最大
    int sum[205];
    int main()
    {
        int n;
        scanf("%d",&n);
        memset(sum,0,sizeof(sum));
        memset(dpmin,INF,sizeof(dpmin));
        memset(dpmax,-1,sizeof(dpmax));
        for(int  i =1;i<=n;i++){
            scanf("%d",&stone[i]);
            sum[i] = sum[i - 1] + stone[i];
            dpmin[i][i] = 0;
            dpmax[i][i] = 0;
        }
        for(int i = 1;i<=n;i++){
            sum[i+n] = sum[i+n-1]+stone[i];//展开的n后面的n-1~1重量
            dpmin[i+n][i+n] = 0;
            dpmax[i+n][i+n] = 0;
        }
        for(int len = 1;len<=n;len++){//长度还是最大n
            for(int j = 1;j+len<=2*n;j++){//起点枚举最大到2*n-1,ends<=2*n-1
                int ends = j+len - 1;
                for(int i = j;i<ends;i++){//注意!i<ends!!!因为i=ends时,dp[ends+1][ends]是不成立的!
                    dpmin[j][ends] = min(dpmin[j][ends],dpmin[j][i]+dpmin[i+1][ends]+sum[ends]-sum[j-1]);
                    dpmax[j][ends] = max(dpmax[j][ends],dpmax[j][i]+dpmax[i+1][ends]+sum[ends]-sum[j-1]);
                }
            }
        }
        int ansmin = 0xfffffff;
        int ansmax = -1;
        for(int i = 1;i<=n;i++){
            ansmin = min(ansmin,dpmin[i][i+n-1]);//找1~n,2~n~1,3~n~2....的合并n个堆的中最大和最小的值
            ansmax = max(ansmax,dpmax[i][i+n-1]);
        }
        cout<<ansmin<<endl;
        cout<<ansmax<<endl;
        return 0;
    }
    

    五.时间优化(四边形优化,n^2)

    思路:在查找最优分割点的时候,我们浪费了大量时间。那么我们可以把最优分割点保存下来,在查找的时候利用保存的最优分割点来优化查找过程。

    四边形不等式优化:

    (1)功能:用来寻找,s[i][j](i~j的最优分割点)与其他分割点的关系

    (2)不等式内容:如果某东西满足a<b<=c<d且f[a][c]+f[b][d]<=f[a][d]+f[b][c],则说这个东西满足四边形不等式。简而言之:交叉小于包含!

    (3)结论关系:s[i][j-1]<=s[i][j]<=s[i+1][j] 

    (4)证明过程:

     0.证明w满足四边形不等式,这里w是m的附属量,形如m[i,j]=opt{m[i,k]+m[k,j]+w[i,j]},此时大多要先证明w满足条件才能进一步证明m满足条件

     1.证明m满足四边形不等式

     2.证明s[i,j-1]≤s[i,j]≤s[i+1,j]

    (5)证明请参考:点击打开链接

    代码:(以石子归并v2为例)

    #include <iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define INF 0x3f3f3f
    int dp[2005][2005];
    int sum[2005];
    int relation[2005][2005];
    int num[2005];
    int main()
    {
        int n;
        scanf("%d",&n);
        memset(sum,0,sizeof(sum));
        memset(dp,0x3f,sizeof(dp));
        for(int i = 1;i<=n;i++){
            scanf("%d",&num[i]);
            dp[i][i] = 0;
            relation[i][i] = i;
            sum[i] = sum[i-1] + num[i];
        }
        for(int i = 1;i<=n;i++){
            sum[i+n] = sum[i+n-1] +num[i];
            relation[i+n][i+n] = i+n;//分割点初始化
            dp[i+n][i+n] = 0;
        }
        for(int len = 1;len<=n;len++){
            for(int j = 1;j+len<=2*n;j++){
                int ends = j+len - 1;
                for(int k = relation[j][ends-1];k<=relation[j+1][ends];k++){//k的范围
                    if(dp[j][ends]>dp[j][k]+dp[k+1][ends]+sum[ends]-sum[j-1])
                    {
                        dp[j][ends]=dp[j][k]+dp[k+1][ends]+sum[ends]-sum[j-1];
                        relation[j][ends] = k;
                    }
                }
            }
        }
        int ans = 0xfffffff;//一定要开0xfffffff不然错QAQ
        for(int i = 1;i<=n;i++){
            ans = min(ans,dp[i][i+n-1]);
        }
        printf("%d\n",ans);
        return 0;
    }
    

    六.四道入门题目(难点在于怎么找状态转移方程)

    1.Poj2955 括号匹配(一)

    (1)题意:给出一个的只有'(',')','[',']'四种括号组成的字符串,求 最多 有多少个括号满足题目里所描述的完全匹配。

    (2)思路:这里的状态转移是以一个if为基础的,如果s[i]与s[j]匹配,那么明显的dp[i][j] = dp[i+1][j-1]+2;然后在这个基础上枚举分割点k.

    (3)状态转移方程:dp[i][j]表示第i~j个字符间的最大匹配字符数。

    if(s[i] 与 s[j]匹配) dp[i][j] = d[[i+1][j-1] +2;

    dp[i][j] = max(dp[i][j],dp[i][k]+dp[k+1][j]);

    代码:

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int dp[105][105];
    int main()
    {
        char s[105];
        while(scanf("%s",s+1)!=EOF)
        {
            memset(dp,0,sizeof(dp));//dp初始化为0,因为一方面是找最大之,一方面初始匹配数为0
            int len = strlen(s+1);//dp[i][i]不用处理,因为自己和自己不匹配就是0
            if(s[1]=='e')break;
            for(int l = 1;l<=len;l++){
                for(int i = 1;i+l<=len+1;i++){
                    int j= i+l-1;
                    if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']')){//如果匹配,先更新
                        dp[i][j] = dp[i+1][j-1]+2;
                    }
                    for(int k = i;k<j;k++){//k<j
                        dp[i][j] = max(dp[i][j],dp[i][k]+dp[k+1][j]);
                    }
                }
            }
            cout<<dp[1][len]<<endl;
        }
        return 0;
    }
    

    2.Poj1651 抽卡片

    (1)题意:给你n个数字,要求不能删除两端点的数字,然后删除其他数字的代价是该数字和左右相邻数字的乘积,问把数字(除端点)删完后的最小总代价。

    (2)思路:因为最后都要删掉中间所有的数字,所以我们分隔一个个小区间删数字,合并区间求最小。那么我们的状态就是目前删掉的数字区间,但是我们分割的时候的意思是抽一个卡片出来,所以这个卡片不能在已经抽出的状态里面,所以dp[i][j]里面是不包含j卡片的!

    (3)状态转移方程:dp[i][j]表示抽出第i~j-1张卡片时候的最小值

    dp[i][j] = min(dp[i][j],dp[i][k] + dp[k+1][j] +num[i-1]*num[k]*num[j]);

    代码:

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int dp[105][105];
    int num[105];
    int main()
    {
        int N;
        cin>>N;
        memset(dp,0x3f,sizeof(dp));//dp初始化为inf,因为找最小值
        for(int i = 1;i<=N;i++){
            cin>>num[i];
            dp[i][i] = 0;//dp[i][i]要初始化,作为由小到大累计的初始条件,自己取出自己就是为0
        }
        for(int len = 1;len<=N;len++){
            for(int i = 2;i+len<=N+1;i++){//起点从2开始,因为不包括两端点
                int j = i+len-1;
                for(int k = i;k<j;k++){
                    dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]+num[i-1]*num[k]*num[j]);
                }
            }
        }
        cout<<dp[2][N]<<endl;//由dp[i][j]的定义,输出合并第2~N-1个卡片的结果
        return 0;
    }
    

    3.整数划分(四)

    (1)题意:给出两个整数 n , m ,要求在 n 中加入m - 1 个乘号,将n分成m段,求出这m段的最大乘积

    (2)思路:这里给的乘号是有限个,所以状态方程里必须包含使用乘号的个数,此外还要包含区间长度。所以怎么用二维dp实现包含m和n,我们可以用dp[i][j]表示在第1~i个字符里插入j个乘号的最大值。

    (3)状态转移方程 dp[i][j]表示在第1~i个字符里插入j个乘号的最大值;用num[i][j]表示第i~j个字符表示的数字;

    dp[i][j] = max(dp[i][j],dp[k][j-1]*num[k+1][i])

    代码:

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    ll dp[50][50];
    ll num[50][50];
    int main()
    {
        int T;
        scanf("%d",&T);
        char s[100];
        while(T--)
        {
            int m;
            scanf("%s%d",s+1,&m);
            int len = strlen(s+1);
            memset(dp,0,sizeof(dp));//初始化dp
            memset(num,0,sizeof(num));
            for(int i = 1; i<=len; i++)
            {
    
                for(int j = i; j<=len; j++)
                {
                    for(int k = i;k<=j;k++){
                        num[i][j]*=10;
                        num[i][j]+=(s[k]-'0');
                    }
                }
                dp[i][0] = num[1][i];//初始插入0个乘号时是自己,由小到大累计的基础
            }
            for(int j = 1;j<m;j++){//乘号个数由1~m-1个
                for(int i = 1;i<=len;i++){//结尾坐标(表示长度)
                    for(int k = 1;k<i;k++){//分割点插入第j个乘号
                        dp[i][j] = max(dp[i][j],dp[k][j-1]*num[k+1][i]);
                    }
                }
            }
            cout<<dp[len][m-1]<<endl;//输出在1~len插入m-1个乘号的结果
        }
        return 0;
    }
    

    4.最多回文子串 hdu4632

    (1)题意:给你一个字符串,求出其最多的可构成的回文字串(不要求连续),注:这里不同的回文字串只要求位置不同即可视为不同,如:aaaaa 的最多回文子串数目是 31.

    (2)思路:用dp[i][j]表示状态,表示i~j里最多的回文字串数目,假设现在我们要求dp[i][j]:

    a.首先:由前一个状态知:dp[i][j] = dp[i+1][j]并上dp[i][j-1] (因为区间尽可能大而且状态要在dp[i][j]之前,而且回文子串不要求 连续),由容斥原理得:dp[i+1][j] U dp[i][j-1] = dp[i+1][j]+dp[i][j-1] - dp[i+1][j] n dp[i][j-1]

                                                                       =  dp[i+1][j]+dp[i][j-1] - dp[i+1][j-1]

    注意:这是一个固定的状态,每一个状态都由这个公式推出初始状态,是必须的,不是可选择地

    b.其次:如果s[i] == s[j] ,那么两端单独就可以构成回文子序列,而且与dp[i+1][j],dp[i][j-1],dp[i+1][j-1],中的回文序列又可以构成新的回文序列,所以此时dp[i][j] = dp[i+1][j] U dp[i][j-1] + dp[i+1][j-1] +1;而dp[i][j]已经更新为 dp[i+1][j] U dp[i][j-1],所以dp[i][j] = dp[i][j] + dp[i+1][j-1] +1;

    (3)状态转移方程: dp[i][j]表示i~j内最多的回文字串数目

    dp[i][j] = dp[i+1][j]+dp[i][j-1] -dp[i+1][j-1] (容斥)

    if(s[i] == s[j]) dp[i][j] = dp[i][j] +dp[i+1][j-1] +1; (思维)

    注:这里因为容斥时有减法,所以要先加上模再取模,要不会出

    现负数!

    代码:

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    char s[1005];
    int dp[1005][1005];
    int main()
    {
        int T;
        scanf("%d",&T);
        int t = 0;
        while(T--){
            t++;
            scanf("%s",s+1);
            memset(dp,0,sizeof(dp));
            int len = strlen(s+1);
            for(int i = 1;i<=len;i++)dp[i][i] = 1;//自己是长度为1的
            for(int l = 1;l<=len;l++){
                for(int i = 1;i+l<=len+1;i++){
                    int j = i+l-1;//容斥原理 dp[i][j] = dp[i+1][j]并dp[i][j-1] (因为是自序列可以不连续)
                    dp[i][j] = (dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]+10007)%10007;
                    if(s[i] == s[j])dp[i][j]=(dp[i][j]+dp[i+1][j-1] + 1)%10007;//如果两端相等,dp[i][j] = 原来的 + 两端与中间每一个回文也可以构成回文(dp[i+1][j-1]) + 两端单独构成一个回文(1)!!!
                }
            }
            printf("Case %d: %d\n",t,dp[1][len]);
    
        }
        return 0;
    }
    

     

    展开全文
  • 数位dp总结 之 从入门到模板

    万次阅读 多人点赞 2016-08-03 14:37:59
    数位dp是一种计数用的dp,一般就是要统计一个区间[le,ri]内满足一些条件数的个数。所谓数位dp,字面意思就是在数位上进行dp咯。数位还算是比较好听的名字,数位的含义:一个数有个位、十位、百位、千位......数的每...
  • 简单dp

    千次阅读 2020-11-03 21:32:34
    简单dp 动态规划是ACM里面一个很重要的算法,同时也是很常用的算法,dp算法的效率高,代码量简单,对思维也有一定考察。以下是我最近学习的简单dp的一些理解极例题。 1,数字三角形: 给定这样一个三角形 5 3 4 7 13...
  • DPB详解

    万次阅读 2020-03-15 08:27:34
    解码图像缓存器(decoded picture buffer,DPB)用于存放解码图像。DPB中既存在参考图像也存在非参考图像,那些不用于参考的图像输出后会被移除出DPB。 DPB的容量由SPS中的sps_max_dec_pic_buffering_minus1字段...
  • dp2px px2dp

    万次阅读 2017-01-19 15:45:29
    /** * 将dp转换成px * @param context * @param dpValue * @return */ public static int dip2px(Context context,float dpValue){ final float scale = context.getResources ().g
  • 状态压缩dp(状压dp)

    万次阅读 多人点赞 2018-07-16 09:05:43
    状压dp是一类比较难理解的dp; 在讲状压dp之前,我们应该清楚所有的dp是解决多阶段决策最优化问题的一种思想方法; 请注意多阶段这三个字: 经过前面三种背包的学习,可以发现如何定义状态是解决动态规划最重要的...
  • DP概述和常见DP面试题 --算法竞赛专题解析(11)

    千次阅读 多人点赞 2020-04-11 10:18:09
    DP的概念和基本操作;DP的设计、方程推导、记忆化编码、递推编码、滚动数组;常见的DP面试题。
  • 对于这个历史遗留性问题每次回头处理起来着实让人头疼 解决方案有以下几种 1.张鸿洋已经实现了并且在githup上的Android...至于字体大小或者控件高度,工具满天飞的现在设计师连dp都会给你标号的,是个Android程序
  • 小白dp总结

    千次阅读 2020-10-11 21:33:28
    根据目前我所做的几个dp题的小总结 背包问题经过简化过就先不参与比较 背包总结 一下仅个人理解: 根据所求的不同dp数组代表不同含义 dp主要是填表的过程----->填表的顺序 由后面需要用到前面求出的值有关 冰水...
  • 概率dp习题

    千次阅读 热门讨论 2020-11-01 17:41:53
    概率dpdpdp习题 前言:太菜了,没学这个知识点,来补...首先初始化:dp[i][0]=1,dp[0][j]=0,i∈[1,w],j∈[0,b]dp[i][0]=1,dp[0][j]=0,i\in[1,w],j\in[0,b]dp[i][0]=1,dp[0][j]=0,i∈[1,w],j∈[0,b] 然后状态转移: 分四
  • NC 201607 DP

    千次阅读 2020-07-01 11:08:19
    题意 传送门 NC 201607 题解 题意其实是求节点 111 ...dp[i]=∑e(i,j)∈Edp[j]dp[i]=\sum\limits_{e(i,j)\in E} dp[j]dp[i]=e(i,j)∈E∑​dp[j] #include <bits/stdc++.h> using namespace std; #define maxn 100
  • 动态规划之树形DP,区间DP

    千次阅读 2019-07-19 20:38:51
    树形DP 树形 DP,即在树上进行的 DP。由于树固有的递归性质,树形 DP 一般都是递归进行的。 以下面这道题为例,介绍一下树形 DP 的一般过程。 https://www.luogu.org/problemnew/show/P1352 我们可以定义 dp[i][0/1...
  • 2020寒假培训期望dp(概率dp)题解

    千次阅读 2020-01-11 16:50:09
    概率期望dp一般都是逆推。正推的话要计算期望的期望,非常麻烦!一般来说,总有一个末状态是一定会发生,从这个状态开始逆推可以简化许多问题。 期望dp和普通的dp的不同处。普通的dp可能纪录的是dp[i]到了i这个状态...
  • 计数dp

    千次阅读 2018-03-30 14:31:13
    i的情况,可以假设有一个大小为i的集合,dp[i][j-i]是对j-i的i划分,dp[i][j]的状态就可以从前者转移而来,即前者划分所对应的大小为i集合所有元素+1之后得到的新集合,可以保证这个新集合所有的元素都&gt;0;(也就...
  • dp计算

    千次阅读 2017-04-20 16:25:07
    1.首先什么是dp?什么是px?dp和px有什么区别?dp与px之间的转换关系? 1.什么px?图像显示的基本单元,我们知道屏幕是由很多点组成的,因为点特别小,所以我们看起来就像是一片的。那其中的每一个点就是像素点,而px呢...
  • 数位DP入门+数位DP模板

    千次阅读 2017-08-20 11:58:20
    数位dp是一种计数用的dp,一般就是要统计一个区间[le,ri]内满足一些条件数的个数。所谓数位dp,字面意思就是在数位上进行dp咯。数位还算是比较好听的名字,数位的含义:一个数有个位、十位、百位、千位......数的每...
  • DP-记录

    千次阅读 2020-08-11 17:11:07
    这里写自定义目录标题DP记录四字键盘对于不同的DP状态定义有不同的解法方法1:传统方法,暴力列举所有状态方法2:“贪心”+dp DP记录 四字键盘 即A,Crtl+A,Crtl+C,Crtl+V四种键盘,使用它们在一个啥也没有的空...
  • DP总结

    千次阅读 2018-08-31 10:45:58
    DP总结 一. 本质 递归转递推。 二. 前提 问题具有最优子结构性质。如果问题的最优解所包含的 子问题的解也是最优的,我们就称该问题具有最优子结 构性质。 无后效性。当前的若干个状态值一旦确定,则...
  • DisplayPort-DP接口知识

    万次阅读 2019-05-23 10:38:45
    DP接口(DisplayPort)是一种图像显示接口,它不仅可以支持全高清显示分辨率(1920×1080),还能支持4k分辨率(3840×2160),以及最新的8k分辨率(7680×4320)。DP接口不仅传输率高,而且可靠稳定,其接口传输的信号由...
  • 巧克力蛋糕 DP

    千次阅读 2020-03-15 17:14:42
    题目大意,现在有一个L高度的容器,还有三种巧克力:1.高1cm的黑巧克。2.高1cm的白巧克。...然后看了一下题解发现是dp(题解说是简单dp,但是我看了很久才懂)。 我们使用一个二维数组dp[max][5],其中...
  • 数位dp

    万次阅读 2018-11-17 21:38:32
    数位dp是一种计数用的dp,一般就是要统计一个区间[le,ri]内满足一些条件数的个数。所谓数位dp,字面意思就是在数位上进行dp咯。数位还算是比较好听的名字,数位的含义:一个数有个位、十位、百位、千位...
  • dp模式是什么意思 DP:显示图片 (DP: Display Picture) DP is an abbreviation of the Display Picture. It is also called a profile picture. It denotes a picture which is in commonly used as a display ...
  • 树形dp

    千次阅读 2018-08-15 19:26:11
    这是一种在树上的dp,它与线性dp不同,与线性dp的顺序是不同的所以其实树形dp就是 树上dp是一种在树状结构上进行dp的一种,各个阶段呈现树状关系的时候也可以采用树形dp。 2.分类 其实这里也有很多类了,树上...
  • 背包 dp

    千次阅读 2015-01-23 12:33:51
    #include #include #include using namespace std; int dp[100002]; int main() {  int n;  while(cin>>n,n!=0)  {  int a[1200];  memset(dp,0,sizeof(dp));  i
  • 概率dp学习笔记+概率dp

    千次阅读 2018-08-19 10:32:49
    2.期望从后往前找,一般dp[n]=0,dp[0]是答案; 3.解决过程,找出各种情况乘上这种情况发生的概率,求和; 【1】A - Collecting Bugs 我是题目链接 题意:一个软件有s个子系统,会产生n种bug。 某人一天发现.....
  • DP_区间DP专辑】

    千次阅读 2013-04-13 17:11:50
    区间DP是一类在区间上进行动态规划的最优问题,一般是根据问题设出一个表示状态的dp,可以是二维的也可以是三维的,一般情况下为二维。然后将问题划分成两个子问题,也就是一段区间分成左右两个区间,然后将左右两个...
  • Codeforces 1110D Jongmah dp

    万次阅读 2020-10-02 23:38:09
    可以发现同样三个数字组成的顺子不会超过三组(可以当作三个刻子处理),因此可以定义dp[i][j][k]dp[i][j][k]dp[i][j][k]表示前iii种牌,i−1,i,i+1i-1,i,i+1i−1,i,i+1组成的顺子数量为jjj,i,i+1,i+2i,i+1,i+2i,i+1,i+2...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 251,289
精华内容 100,515
关键字:

dp