就是太菜了
主要分为:
其实DP就是一个类似递推的算法。
题
题目描述:
给定一个序列,从中选取若干个数,使得这一组数组成的序列a满足 i < j 且 a[i] < a[j],求这个序列的最长长度。
#include
const int MAXN = 5005;
int a[MAXN], dp[MAXN];
int main() {
int n;
scanf ("%d", &n);
int ans = 0, s = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
dp[i] = 1; //初始化
for(int j = 1; j < i; j++) {
if(a[i] > a[j] && dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1;
}
}
if(dp[i] > ans) {
ans = dp[i];
s = i;//转移答案
}
}
printf("%d\n", ans);
return 0;
}
经GM权威讲解:我们知道了当一个问题的状态转移方程具有最优子结构与重叠子问题,则其可用动态规划求解。
那么我们开始下一道题!
题目描述:
给定一个整数序列A1A2A3….An。求它的一个递增子序列,使子序列的元素个数尽量多,元素不一定要求连续。
(特别注意这里:
输出格式
第1行:1个整数k,表示最长上升子序列的长度。
第2行:k个用单个空格分开的整数,表示找到了最长上升子序列。如果有多个长度等于k的子序列,则输出最靠前的1个。
)
#include
int prev[1005];
const int MAXN = 100005;
int a[MAXN], dp[MAXN];
using namespace std;
void print(int i){
if(prev[i]==i){
printf("%d",a[i]);
return;
}
print(prev[i]);
printf(" %d",a[i]);
}
int main() {
int n;
scanf ("%d", &n);
int ans = 0, s = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
dp[i] = 1;
for(int j = 0; j < i; j++) {
if(a[i] > a[j] && dp[j] + 1 > dp[i]) {
dp[i] = dp[j] +1;
prev[i]=j;
}
}
if(dp[i] > ans) {
ans = dp[i];
s = i;
}
}
printf("%d\n", ans);
print(s);
return 0;
}
#include
int prev[1005];
const int MAXN = 100005;
int a[MAXN], dp[MAXN];
using namespace std;
void print(int i){
if(prev[i]==i){
printf("%d",a[i]);
return;
}
print(prev[i]);
printf(" %d",a[i]);
}
int main() {
int n;
scanf ("%d", &n);
int ans = 0, s = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
dp[i] = 1;
prev[i]=i;
for(int j = 0; j < i; j++) {
if(a[i] > a[j] && dp[j] + 1 > dp[i]) {
dp[i] = dp[j] +1;
prev[i]=j;
}
}
if(dp[i] > ans) {
ans = dp[i];
s = i;
}
}
printf("%d\n", ans);
print(s);
return 0;
}
那么这道题呢有几种不同的做法:
#include
#include
#include
using namespace std;
int a[105][105] = {0};
int dp[105][105] = {0};
int main(){
int n;
cin>>n;
for( int i = 1; i <= n; i++ )
for( int j = 1; j <= i; j++ )
cin>>a[i][j];
for( int i = 1; i <= n; i++ )
for( int j = 1; j <= i; j++ )
dp[i][j] = max(dp[i-1][j-1],dp[i-1][j]) + a[i][j];
int ans = 0;
for( int j = 1; j <= n; j++ )
ans = max(ans,dp[n][j]);
cout<<ans<<endl;
return 0;
}
1. 从根结点13出发,选取他的两个方向中的一条支路,当到了倒数第二层时,每个节点其后继仅有的两个节点,可以直接比较,选择最大值为前进方向,从而求得从根节点开始到底端的最大路径。
2. 自底向上:(给出递推式和终止条件)
-从底层开始,本身即为最大数
-从倒数第二层开始取决于底层数据
······
由此推下去
#include
#include
using namespace std;
const int MAXN=1005;
int a[MAXN][MAXN],f[MAXN][MAXN],n,ans;
void dfs(int x,int y,int Curr){
if(x==n){
if(Curr>ans)ans=Curr;
return;
}
dfs(x+1,y,Curr+a[x+1][y+1]);
dfs(x+1,y+1,Curr+a[x+1][y+1]);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
scanf("%d",&a[i][j]);
ans=0;
dfs(1,1,a[1][1]);
printf("%d",ans);
return 0;
}
#include
#include
#include
using namespace std;
const int MAXN=505;
int a[MAXN][MAXN],f[MAXN][MAXN],n;
int dfs(int x,int y){
if (f[x][y]==-1){
if(x==n)f[x][y]=a[x][y];
else f[x][y]=a[x][y]+max(dfs(x+1,y),dfs(x+1,y+1));
}
return f[x][y];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++){
scanf("%d",a[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
f[i][j]=-1;
dfs(1,1);
printf("%d",f[1][1]);
return 0;
}