多阶段决策过程的最优化问题
重要概念
·阶段
·描述状态
·状态转移方程
线性模型
【分析】
根据样例找出规律即可
当前位置的数累加上下面两个位置中的最大值
【代码】
#include <bits/stdc++.h>
using namespace std;
int a[1005][1005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){//注意是小于等于i
cin>>a[i][j];
}
}//输入金字塔
for(int i=2;i<=n;i++){//从第二行开始遍历
for(int j=1;j<=i;j++){
a[i][j]+=max(a[i-1][j-1],a[i-1][j]); //规律qwq
}
}
int k=0;
for(int i=1;i<=n;i++){
if(a[n][i]>k) k=a[n][i];//输出最大值
}
cout<<k;
return 0;
}
【分析】
好吧我也不知道说什么了,详见代码。
打表!!!首先初始化l和suf,然后遍历,比较大小,你赋给我我赋给你
(数列中的数是可以相等的)
【代码】
#include <bits/stdc++.h>
using namespace std;
struct S{
int x,l,suf;//x表示数本身,l表示序列长度,suf表示后缀
}a[205];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x;//输入数本身
a[i].l=1;
a[i].suf=-1;//令初始序列长度为1(数本身),后缀为-1,即无后缀
}
for(int i=n-1;i>=1;i--){//从后往前看
int hi,hx;//hi用来标记后缀下标,hx用来标记后缀长度
hx=0;//假设后缀初始长度为0
for(int j=i+1;j<=n;j++){//
if(a[j].x>=a[i].x && a[j].l>hx){//如果后面有一个数大于当前数(a[i].x),且该数的后面的序列长度大于0
hx=a[j].l;//将其序列长度赋给hx
hi=j;//并将该数的下标赋给hi
}
}
if(hx!=0){//不等于0说明上述for循环内容成立
a[i].l=hx+1;//a[i].l会等于上一个数的序列长度+1,a[i].x成为下一个数
a[i].suf=hi;//a[i].suf由j而来,则将hi赋值
}
}
int maxi,maxn=0;//maxi用来标记下标,maxn用来标记数
for(int i=1;i<=n;i++){//从1到n
if(a[i].l>maxn){
maxn=a[i].l;
maxi=i;//和上面类似 从而得到序列元素最大数
}
}
cout<<"max="<<maxn<<endl;//注意输出格式
int k;
k=maxi;//k用来表示后缀下标
while(k!=-1){//有后缀时
cout<<a[k].x<<" ";//输出该下标对应的数
k=a[k].suf;//又令k等于该数对应的后缀 即成为下一个被输出数的下标
}
return 0;
}
【分析】
嗯
【代码】
#include <bits/stdc++.h>
#define N 100010
using namespace std;
int a[N],f[N];//a为输入的导弹高度,f用来存储拦截系统的最高高度
int main(){
int n=1;
while(scanf("%d",&a[n])!=EOF) n++;//逐个读入导弹高度
n--;//遍历
f[0]=5000001;//设置第一个拦截系统的第一发能达到任意高度
int k=0;//还没有开始拦截
int i;
for(i=1;i<=n;i++){
if(f[k]>=a[i]){//如果当前导弹高度小于该系统当前的最高高度
f[k+1]=a[i];//实时更新最高高度即可
k++;
}
else{//如果大于 进行二分 找到第一个比它小的位置
int l,r,mid;
l=1,r=k;//注意是从1到k
while(l<r){
mid=(l+r)/2;
if(f[mid]>=a[i]) l=mid+1;//当前导弹高度小于f[mid] 即在右边
else r=mid;//大于f[mid] 即在左边
}
f[l]=a[i];//更新
}
}
cout<<k<<endl;//输出能拦截的导弹数
memset(f,-1,sizeof(f));//每次循环初始化为-1
int m=0;//刚开始系统数为0
f[0]=-1;//嗯
for(i=1;i<=n;i++){
if(f[m]<a[i]){
f[m+1]=a[i];
m++;
}//如果当前导弹高度大于系统最高高度 需要重新配置系统m++ 并更新最高高度
else{//如果小于等于
int z;
z=lower_bound(f,f+m+1,a[i])-f;//从f到f+m+1中寻找大于等于a[i]的数(得到地址),减去f即得到下标
f[z]=a[i];//更新
}
}
cout<<m;
return 0;
}
【拓展】
lower_bound() 函数用于在指定区域内查找不小于目标值的第一个元素,定义在<algorithm>
头文件中。也就是说,使用该函数在指定范围内查找某个目标值时,最终查找到的不一定是和目标值相等的元素,还可能是比目标值大的元素。
格式: lower_bound( first , last , a )
其中a为目标值,具体见代码。
例4 OJ261 城市交通路网
【代码】
#include <bits/stdc++.h>
using namespace std;
const int N=15;
int a[N][N],b[N],f[N];//a为交通网,b用来记录最省交通费,f用来记录路径
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
memset(b,0x3f,sizeof(b));//初始化
b[n]=0;//刚开始为0
for(int i=n;i>=1;i--){//从后往前推
for(int j=i+1;j<=n;j++){
if(a[i][j]&&b[i]>b[j]+a[i][j]){
b[i]=b[j]+a[i][j];
f[i]=j;//比较得出最省费用,再将当前城市存入f
}
}
}
cout<<"minlong="<<b[1]<<endl;//输出费用
for(int i=1;i!=n;i=f[i]) cout<<i<<" ";
cout<<n;//打印路径
return 0;
}
【分析】
1.运用01背包(或许吧)
2.比较最后从上面或是从左边来的数的大小,得到最大数。
【代码】
#include <bits/stdc++.h>
using namespace std;
int a[105][105],b[105][105];//a为矩形花生地,b用来计数
int r,c;
int main(){
int T;
cin>>T;
while(T--){
cin>>r>>c;
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
b[i][j]=max(b[i][j-1],b[i-1][j])+a[i][j];//比较取最大值
}
}
cout<<b[r][c]<<endl;
}
return 0;
}