这里提供一个 O(nm) 复杂度做法。
记 f(i,j) 表示前 i 个花瓶放了 j 朵花的最大美观程度,那么每个状态只有两个选择,要么选这个花瓶要么不选,并且如果选了这个花瓶便只能放第 j 朵花,这样的设计自然地保证了花的位置与顺序不会冲突。
状态转移方程(有点像背包):f(i,j)=max 其中 w(i,j) 表示第 j 朵花在第 i 个花瓶的美观度。
起点:f(i,0)=0\ (0\leq i\leq n),其余为负无穷。
目标:\max\left(f(i,m)\right)\ (m\leq i\leq n),m 为花种数,n为花瓶数。
(好像还可以压成一维……
#include <bits/stdc++.h>
using namespace std;
int n,m,ans=-1e9,ed,f[105][105],w[105][105];
struct Path{int x,y;}p[105][105];
//记路径的数组,p[i][j].x表示(i,j)这个状态是从哪个状态转移过来的
//p[i][j].y表示(i,j)这个状态是选了哪个花瓶后被更新的
void print(int now,int cnt)
{
if(!cnt) return;
print(p[now][cnt].x,cnt-1);
printf("%d ",p[now][cnt].y);
}
int main()
{
scanf("%d%d",&m,&n); //m,n意义如上
for(int i=1;i<=m;++i)
for(int j=1;j<=n;++j)
scanf("%d",&w[j][i]); //反过来读
memset(f,0xcf,sizeof(f));
for(int i=0;i<=n;++i) f[i][0]=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=min(m,i);++j)
{
f[i][j]=f[i-1][j]; p[i][j]={p[i-1][j].x,p[i-1][j].y};
if(f[i][j]<f[i-1][j-1]+w[i][j])
f[i][j]=f[i-1][j-1]+w[i][j],p[i][j]={i-1,i};
}
for(int i=m;i<=n;++i) ans=max(ans,f[i][m]);
for(int i=m;i<=n;++i) if(f[i][m]==ans) {ed=i; break;}
printf("%d\n",ans);
print(ed,m);
return 0;
}