背包类型的dp
设f(i,j)为 "将编号1...i的鲜花放到花瓶1...j能够得到的最大吸引力"
对于f(i,j),有两种可能性,要么第j个花瓶是空的,要么第j个花瓶放着编号为i的鲜花
于是可以得到转移方程:f(i, j) = max { f(i, j - 1) , f(i - 1, j - 1) + a[i][j] }
#include <cstdio>
#include <vector>
#include <cmath>
#include <cassert>
using namespace std;
int F, V;
vector< vector<int> > a;
vector< vector<int> > f;
vector< vector<int> > w;
vector<int> pos;
int directlyPut(int n) {
int i;
int ans = 0;
for (i = 1; i <= n; ++i)
ans = ans + a[i][i];
return ans;
}
template <class VVType, class T>
void make2DVector(VVType &a, int d, int f, const T &initValue) {
int i, j;
a.resize(d);
for (i = 0; i < d; ++i) {
a[i].resize(f);
for (j = 0; j < f; ++j)
a[i][j] = initValue;
}
}
void traceBackAns() {
pos.resize(F + 1);
int i = F, j = V;
while (1) {
assert(w[i][j] == 0 || w[i][j] == 1);
if (w[i][j] == 0) {
j = j - 1;
continue;
} else {
pos[i] = j;
i = i - 1;
j = j - 1;
}
if (i == 0) break;
}
}
int dp() {
int j, i;
f[1][1] = a[1][1];
w[1][1] = 1;
for (j = 2; j <= V; ++j) {
if (f[1][j-1] >= a[1][j]) {
f[1][j] = f[1][j-1];
w[1][j] = 0;
} else {
f[1][j] = a[1][j];
w[1][j] = 1;
}
}
for (i = 2; i <= F; ++i) {
for (j = i; j <= V; ++j) {
if (i == j) {
f[i][j] = directlyPut(j);
w[i][j] = 1;
} else {
if (f[i][j-1] >= f[i-1][j-1] + a[i][j]) {
f[i][j] = f[i][j-1];
w[i][j] = 0;
} else {
f[i][j] = f[i-1][j-1] + a[i][j];
w[i][j] = 1;
}
}
}
}
printf("%d\n", f[F][V]);
traceBackAns();
for (i = 1; i <= F; ++i) {
printf("%d", pos[i]);
if (i != F) printf(" ");
}
printf("\n");
}
void input() {
scanf("%d %d", &F, &V);
int i, j;
int tmp;
make2DVector(a, F + 1, V + 1, 0);
assert(a.size() == F + 1 && a[0].size() == V + 1);
for (i = 1; i <= F; ++i) {
for (j = 1; j <= V; ++j) {
scanf("%d", &tmp);
a[i][j] = tmp;
}
}
}
int main() {
int i;
input();
make2DVector(f, F + 1, V + 1, 0);
make2DVector(w, F + 1, V + 1, -1);
dp();
return 0;
}