Description
在某款极具技术含量的网络游戏中,佳佳靠着他的聪明智慧垄断了游戏中的油田系统。油田里有许多油井,这些油
井排成一个M*N的矩形。每个油井都有一个固定的采油量。每两个相邻的油井之间有一条公路,这些公路是油井与
油井之间唯一的运油方式。佳佳的领地在油田的右方和下方,他需要把采到的油通过这些公路运输到他的领地。为
了保证采到的油以最快的方式供给右方和下方的领地,对于每个油井,佳佳总是将采到的油分成非空的两部分将其
中一部分沿公路一直向右运输到油田的右边界,将另一部分沿公路一直向下运输到油田的下边界。然而树大招风,
网络游戏中的GM以保证游戏公平为由,要求佳佳主动贡献出K个油井。更惨的是,失去某些油井不单意味着采油量
减少,这还将会导致运输线路的中断。如果佳佳贡献出了某个油井,那么所有要经过这个油井的运输任务将无法完
成。佳佳想保证贡献K个油井之后自己的损失最小(损失即为失去的所有油井的采油量之和),而他希望其他的所
有油井还能够像往常一样正常运输。于是他向你求救,希望你能帮助他实现他的想法。
Input
第一行有三个用空格隔开的正整数M,N和K,它们分别表示油田的长、宽和佳佳需要贡献出的油田数。
以下N行中每行有M个用空格隔开的正整数。这些正整数保证不超过10000,它们描述了油田中各个油井的采油量。
输入数据保证K<=M*N,M<=60,N<=60。
Output
一个整数,表示佳佳最少要损失的采油量。
Sample Input
5 3 4 3 4 1 4 5 1 10 7 8 13 3 5 8 9 11
Sample Output
9 佳佳贡献出下面标有“x”的油井是符合条件的最小损失方案。 x x x 4 5 x 10 7 8 13 3 5 8 9 11
分析
根据题目要求我们可以发现,被舍弃的油井一定是从左上角向右下角递减,或者说向左上角聚集。
我们可以把状态设计成三维(i,j,k)表示第i行舍弃了j个油井,目前为止共舍弃了k个油井。
然后我们枚举上一行舍弃的数量l,到上一行为止总共舍弃的数量就是k - j
那么就有状态转移方程
dp[i][j][k] = min(dp[i][j][k], dp[i - 1][l][k - j] + w[i][j]);
注意上界优化。
代码
#include<bits/stdc++.h>
using namespace std;
int n, m, kk;
int w[67][67];
int dp[67][67][3617];
int ans = INT_MAX;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return x * f;
}
int main() {
m = read(), n = read(), kk = read();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
w[i][j] = w[i][j - 1] + read();
}
}//前缀和
memset(dp, 0x3f3f3f3f, sizeof dp);
for (int i = 1; i <= n; i++) {
dp[i][0][0] = dp[0][i][0] = dp[0][0][i] = 0;
}//初始化
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= min(m, kk); j++) {//上界优化,当前行最多舍弃数量
for (int k = j; k <= min(m * i, kk); k++) {//上界优化,到目前为止最多舍弃数量
for (int l = j; l <= min(m, kk); l++) {//上界优化,同j循环
dp[i][j][k] = min(dp[i][j][k], dp[i - 1][l][k - j] + w[i][j]);
}
}
}
}
for (int i = 0; i <= min(m, kk); i++) {
ans = min(ans, dp[n][i][kk]);
}
printf("%d", ans);
return 0;
}