橱窗布置(洛谷P1854)
https://www.luogu.com.cn/problem/P1854
问题实际就是给定F束花和V个花瓶,以及各束花放到不同花瓶中的美学值,要求你找出一种摆放的方案,使得在满足编号小的花放进编号小的花瓶中的条件下,美学值达到最大。
将问题进行转化,找出问题的原型。首先,看一下上述题目的样例数据表格。
将摆放方案的要求用表格表现出来,则摆放方案需要满足:每行选且只选一个数(花瓶);摆放方案的相邻两行中,下面一行的花瓶编号要大于上面一行的花瓶编号两个条件。
这时可将问题转化为:给定一个数字表格,要求编程计算从顶行至底行的一条路径,使得这条路径所经过的数字总和最大(要求每行选且仅选一个数字)。
同时,路径中相邻两行的数字,必须保证下一行数字的列数大于上一行数字的列数。
看到经过转化后的问题,发现问题与“数学三角形”问题十分相似,
因此也采用相似的写法
标程代码
···cpp
include
include
include
using namespace std;
int main()
{
int a[101][101],b[101][101],c[101][101],d[101]; //a[i][j] 花束i放在花瓶j中的美学值
//b[i][j] 前i束花放在前j个花瓶中的最优解
//c[i][j] 在b[i][j]的最优解中,花束i-1的位置
int f,v,i,j,k,max; //f , v 花束和花瓶的数目
cin>>f>>v;
for (i=1;i<=f;i++)
for (j=1;j<=v;j++)
cin>>a[i][j];
memset(b,128,sizeof(b)); //这样处理,可以保证每束花都放进花瓶
for (i=1;i<=v-f+1;i++) //初始化第1束花放在第i个花瓶的情况
b[1][i]=a[1][i];
for (i=2;i<=f;i++)
for (j=i;j<=v-f+i;j++)
for (k=i-1;k<=j-1;k++) //枚举花束i-1的位置
if (b[i-1][k]+a[i][j]>b[i][j])
{
b[i][j]=b[i-1][k]+a[i][j]; //更新当前最优解
c[i][j]=k; //前一个花束的位置为k
}
max=-2100000000;
for (i=f;i<=v;i++)
if (b[f][i]>max)
{
max=b[f][i]; //选择全局最优解
k=i; //k最后一束花的位置
}
cout<<max<<endl; //打印最优解
for (i=1;i<=f;i++)
{
d[i]=k;
k=c[f-i+1][k];
}
for (i=f;i>=2;i--)
cout<<d[i]<<" ";
cout<<d[1]<<endl;
}
我的写法(区别是输出路径的方式一个是递推一个是递归)
```cpp
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1010;
int f,v;
int d[maxn][maxn];
int dp[maxn][maxn],pre[maxn][maxn];
void print(int x,int y)
{
if(pre[x][y]==y)
{
printf("%d ",y);
return;
}
print(x-1,pre[x][y]);
printf("%d ",y);
}
int main()
{
scanf("%d%d", &f, &v);
for(int i=1;i<=f;i++)
{
for(int j=1;j<=v;j++)
{
scanf("%d", &d[i][j]);
}
}
for(int i=1;i<=v-f;i++)
{
dp[1][i]=d[1][i];
pre[1][i]=i;
}
for(int i=2;i<=f;i++)
{
for(int j=i;j<=v-f+i;j++)
{
for(int k=1;k<j;k++)
{
if(dp[i-1][k]+d[i][j]>dp[i][j])
{
dp[i][j]=dp[i-1][k]+d[i][j];
pre[i][j]=k;
}
}
}
}
int tx=f,ty,ans=0;
for(int i=f;i<=v;i++)
{
if(dp[f][i]>ans)
{
ans=dp[f][i];
ty=i;
}
}
printf("%d\n",ans);
print(tx,ty);
return 0;
}