luogu1854 花店橱窗布置 题解

朴素的状态为 设 \(f_{i,j}\) 为前 \(i\) 束花,放在前 \(j\) 个花瓶的最大收益。

由题意得,如果把花的编号看作数值,它所在的花瓶编号为下标,那么是不允许逆序对的存在的。编号为 \(i\) 的花必须放在 \(i+1\) 的左边。

也就是说,对于一个 \((i,j)\),前 \(i-1\) 束花只能在 \([1,j-1]\) 这个区间内放置,与后面怎么放无关,「无后效性」。于是我们只需要考虑第 \(i\) 束花要不要放在第 \(j\) 个花瓶中。

所以转移的时候把放与不放两种决策比较一下就好了。 \[ f_{i,j} = \max{\{ f_{i-1,j-1}+c_{i,j},f_{i,j-1} \}} \]

具体看代码。

#include<cstdio>
#include<cstring> 
#include<iostream>
using namespace std;
const int N=105;
int n, m, c[N][N], f[N][N], pre[N][N];
void print(int x,int y) {
	if(!x||!y) return;
	if(pre[x][y]) print(x-1,y-1), printf("%d ",y);
	else print(x,y-1);
}
int main() {
	scanf("%d%d",&n,&m);
	memset(f,0xcf,sizeof(f));
    // 初始化为-inf
	for(int i=1;i<=n;++i) 
		for(int j=1;j<=m;++j) scanf("%d",&c[i][j]);
	for(int i=0;i<=m;++i) f[0][i]=0;
    // 初值
	for(int i=1;i<=n;++i) for(int j=i;j<=m;++j) {
        // j从i到m,减少一些无用状态
		if(f[i-1][j-1]+c[i][j]>f[i][j-1]) f[i][j]=f[i-1][j-1]+c[i][j], pre[i][j]=1;
        // 放置在j
		else f[i][j]=f[i][j-1]; // 不放
	}
	printf("%d\n",f[n][m]);
	print(n,m); puts("");
}

luogu1854 花店橱窗布置 题解
https://yozora0908.github.io/2022/lg1854-solution/
作者
yozora0908
发布于
2022年3月30日
许可协议