《算法笔记上机实验指南》第4章 入门篇(2)第11章 动态规划

it2023-04-02  75

A1007

#include<iostream> using namespace std; const int maxn=100004; int fac[maxn],dp[maxn],s[maxn]={0}; int n; int main() { cin >> n; bool flag=true; //题中的意思是如果所有的数是负数则直接输出0 0 0 for(int i=0; i<n; i++) { cin >> fac[i]; if(fac[i]>=0) //有一个大于等于0的数就设置为flag为false, flag=false; } if(flag==true) //表示的所有的值都是负数 { cout << 0 << " " << fac[0] << " " << fac[n-1]; return 0; } dp[0]=fac[0]; //第1个数的最大值设置为fac[0] for(int i=1; i<n; i++) { //dp[i]=max(fac[i],dp[i-1]+fac[i]); //从第1个位置开始,它这个位置的最大值为前一个位置的最大值加上当前位置的值那一个大 if(dp[i-1]+fac[i]>fac[i]) // { dp[i]=dp[i-1]+fac[i]; s[i]=s[i-1]; } else { dp[i]=fac[i]; s[i]=i; } } int k=0; for(int i=0; i<n; i++) { if(dp[i]>dp[k]) k=i; } cout << dp[k] << " " << fac[s[k]] << " " << fac[k]; return 0; }

A1045

//最长不降子序列 #include<iostream> #include<cstring> using namespace std; const int maxn=10004; //注意最大值 int fac[maxn],HashTable[maxn],dp[maxn]; //fac表示更改的数组 int n1,n,m; int main() { cin >> n1 >> n; int temp,num=0; memset(HashTable,-1,sizeof(HashTable)); //HashTable初始化为-1,为了方便过滤掉有不喜欢的颜色数 for(int i=0; i<n; i++) { cin >> temp; HashTable[temp]=num++; } cin >> m; //输入m int num1=0; for(int i=0; i<m; i++) //有m个循环 { cin >> temp; if(HashTable[temp]>=0) fac[num1++]=HashTable[temp]; //将所喜欢的条带的编号再映射到数组中 } int ans=-1; for(int i=0; i<num1; i++) //在下来使用Lis思路 { dp[i]=1; //设置当前位置的i的值为1,此时肯定是有一个长度的 for(int j=0; j<i; j++) //从0开始遍历,在当前位置i之前 { if(fac[j]<=fac[i] && dp[j]+1>dp[i]) //虽然是访问dp[j]+1>dp[i]的值,但是实质上还是再看i是否能增加到前面中 dp[i]=dp[j]+1; } ans=max(ans,dp[i]); } cout << ans; return 0; } //最长公共子序列 #include<iostream> using namespace std; const int maxn=10004; int n,n1,m; int A[maxn],B[maxn],dp[maxn][maxn]; int main() { cin >> n >> n1; for(int i=1; i<=n1; i++) { cin >> A[i]; } cin >> m; for(int i=1; i<=m; i++) { cin >> B[i]; } for(int i=1; i<=n1; i++) dp[i][0]=0; for(int i=1; i<=m; i++) { dp[0][i]=0; } for(int i=1; i<=n1; i++) for(int j=1; j<=m; j++) { if(A[i]==B[j]) dp[i][j]=max(dp[i-1][j],dp[i][j-1])+1; else dp[i][j]=max(dp[i-1][j],dp[i][j-1]); } cout << dp[n1][m]; return 0; }

A1040

#include<iostream> #include<string> using namespace std; const int maxn=1040; int dp[maxn][maxn]; //dp[i][j]表示从字符串第i位置--第j位置 string s; int main() { getline(cin,s); int len=s.size(); int ans; for(int i=0; i<len; i++) { ans=1; dp[i][i]=1; if(i<len-1) { if(s[i]==s[i+1]) { dp[i][i+1]=1; ans=2; } } } for(int l=3; l<=len; l++) for(int i=0; i+l-1<len; i++) { int j=i+l-1; if(s[i]==s[j] && dp[i+1][j-1]==1) { dp[i][j]=1; ans=l; } } cout << ans; return 0; }

A1068

#include<iostream> #include<algorithm> #include<vector> using namespace std; const int maxn=10005; const int maxv=104; int n,m; int dp[maxn],w[maxn]; vector<int> pre; //前驱数组 bool choice[maxn][maxn]; bool cmp(int a, int b) { return a>b; } int main() { cin >> n >> m; for(int i=1; i<=n; i++) //下标从1开始 { cin >> w[i]; //输入其重量 } sort(w+1,w+n+1,cmp); for(int i=1; i<=n; i++) for(int v=m; v>=w[i]; v--) //这里必须倒叙 { if(dp[v]<=dp[v-w[i]]+w[i]) //原本的dp状态方程为:dp[v]=max(dp[v],dp[v-w[i]]+w[i]) { dp[v]=dp[v-w[i]]+w[i]; //choice其实就是对其数据进行记录的,来记录i,v //choice在这里起到标记的作用 choice[i][v]=true; //choice在这里表示的意思就是当前容量为v时,选择第i件物品 } else { choice[i][v]=false; //表示在容量为v时,不选择第i件物品 } } if(dp[m]!=m) //dp数组表示的是容量为m的情况下的最大价值,而在本题中表示的是在容量为m的情况下的最大钟重量 cout << "No Solution"; else { int index=n,v=m; //因为要输出最小的字典序,所以是从容量为m开始,第n件物品开始(第n件物品此时对应的是字典序最小的值) while(v>0) { if(choice[index][v]==true) //如果之前选择了该物品,则将其对应的重量放到数组pre中,然后在重量减去前面的重量 { pre.push_back(w[index]); v-=w[index]; } index--; //index就是按照顺序一个一个统计 } for(int i=0; i<pre.size(); i++) { if(i!=0) cout << " "; cout << pre[i]; } } return 0; }
最新回复(0)