数字三角形
数塔
Problem Description
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:
有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?
已经告诉你了,这是个DP的题目,你能AC吗?
Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
Sample Input
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
Sample Output
30
这是我大一写的第一道动态规划了
我们用dp[i][j]表示从起始点到i,j位置的最大数字和 ,转移方程便是dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+a[i][j];
其实这还可以从下往上推 那么到起点的数字之和一定是最大的 我这个就是从下往上推的
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 #include<map> 8 #include<set> 9 #include<vector> 10 #include<cstdlib> 11 #include<string> 12 #define eps 0.000000001 13 typedef long long ll; 14 typedef unsigned long long LL; 15 using namespace std; 16 const int N=100+10; 17 int mp[N][N]; 18 int dp[N][N]; 19 int main(){ 20 int t; 21 int n; 22 scanf("%d",&t); 23 while(t--){ 24 scanf("%d",&n); 25 for(int i=1;i<=n;i++) 26 for(int j=1;j<=i;j++)scanf("%d",&mp[i][j]); 27 int maxx=0; 28 for(int i=n-1;i>=1;i--) 29 for(int j=1;j<=i;j++){ 30 mp[i][j]+=max(mp[i+1][j],mp[i+1][j+1]); 31 } 32 cout<<mp[1][1]<<endl; 33 } 34 }
矩形嵌套 (DAG)
有n个矩形 每个矩形有长和宽a b;要使x矩形可以嵌套在y矩形内 必须(x.a<y.a&&x.b<y.b 或者 x.a<y.b&&x.b<y.a);
现在问你选出最多的矩形排成一行 使除了最后以后矩形之外 每个矩形都可以嵌套在下一个矩形
矩形嵌套
- 描述
- 有n个矩形,每个矩形可以用a,b来描述,表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中。你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一个矩形都可以嵌套在下一个矩形内。
- 输入
- 第一行是一个正正数N(0<N<10),表示测试数据组数,
每组测试数据的第一行是一个正正数n,表示该组测试数据中含有矩形的个数(n<=1000)
随后的n行,每行有两个数a,b(0<a,b<100),表示矩形的长和宽
- 输出
- 每组测试数据都输出一个数,表示最多符合条件的矩形数目,每组输出占一行
- 样例输入
-
1 10 1 2 2 4 5 8 6 10 7 9 3 1 5 8 12 10 9 7 2 2
- 样例输出
-
5
题解:首先我们先让每个矩形的长的边 按照从大到小的排个序 Vis[i][j]表示第j个矩形可以嵌套在第i个矩形内
所以我们可以遍历比较一遍 最终根据vis[i][j]得到的就是一个有向无环图
dp[i]表示从节点i出发的最长路长度 ,那么转移方程就是dp[i]=max(dp[j]+1,vis[i][j]=1)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<map> 5 #include<cstdlib> 6 #include<vector> 7 #include<set> 8 #include<queue> 9 #include<cstring> 10 #include<string.h> 11 #include<algorithm> 12 #define INF 0x3f3f3f3f 13 typedef long long ll; 14 typedef unsigned long long LL; 15 using namespace std; 16 const int N=1000+10; 17 int vis[1005][1006]; 18 struct node{ 19 int x,y; 20 }a[N]; 21 int ans[N]; 22 bool cmp(node xx,node yy){ 23 if(xx.x==yy.x)return xx.y>yy.y; 24 else 25 return xx.x>yy.x; 26 } 27 int main(){ 28 int t; 29 scanf("%d",&t); 30 while(t--){ 31 memset(ans,0,sizeof(ans)); 32 memset(vis,0,sizeof(vis)); 33 int n; 34 scanf("%d",&n); 35 // scanf("%d",&n); 36 for(int i=0;i<n;i++){ 37 scanf("%d%d",&a[i].x,&a[i].y); 38 if(a[i].x<a[i].y)swap(a[i].x,a[i].y); 39 } 40 sort(a,a+n,cmp); 41 for(int i=0;i<n;i++) 42 for(int j=i+1;j<n;j++){ 43 if(a[i].x>a[j].x&&a[i].y>a[j].y)vis[j][i]=1; 44 } 45 int maxx=0; 46 for(int i=0;i<n;i++){ 47 ans[i]=1; 48 for(int j=0;j<n;j++){ 49 if(vis[i][j]==1&&ans[i]<ans[j]+1) 50 ans[i]=ans[j]+1; 51 } 52 } 53 // for(int i=0;i<n;i++)cout<<ans[i]<<" "; 54 // cout<<endl; 55 for(int i=0;i<n;i++)maxx=max(ans[i],maxx); 56 cout<<maxx<<endl; 57 } 58 }
最长公共字串和最长公共子序列
拿例子来看吧 X:bacabcefabc Y: baeabcghabc
最长公共字串:abc(字符串必须是连续的 )
最长公共子序列:abcabc(可以不连续)
<1> 最长公共字序列:dp[i][j] 表示储存Xi Yj的最长公共子序列长度
假如 i=0或者j=0 dp[i][j]=0;
假如 i>0&&j>0 Xi==Yj dp[i][j]=dp[i-1][j-1]+1;
假如i>0&&j>0 Xi!=Yj dp[i][j]=max(dp[i-1][j],dp[i][j-1])(自己想想应该很好理解的);
来看一道题:
最长公共子序列
时间限制:3000 ms | 内存限制:65535 KB
难度:3
- 描述
- 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列。
tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common
Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S
称为已知序列的最长公共子序列。
- 输入
- 第一行给出一个整数N(0<N<100)表示待测数据组数
接下来每组数据两行,分别为待测的两组字符串。每个字符串长度不大于1000.
- 输出
- 每组测试数据输出一个整数,表示最长公共子序列长度。每组结果占一行。
- 样例输入
-
2 asdf adfsd 123abc abc123abc
- 样例输出
-
3 6代码板子
<2>最长公共字串