背包问题的变形~~
想法很直观,但是我WA了很多次。但是一改状态表示就立马A了。其实不是状态表示的问题,而是在递推的时候出现了问题。由此我得出状态表示的选择也是有学问的。所以就写了那篇 《动态规划思考》 啦~~~
先贴上感觉最简洁直观的代码:(状态表示为跨完前i个栏后,剩余的力量)
#include <cstdio> #include <algorithm> #define MAXN 110 #define min(a, b) (a < b ? a : b) using namespace std; const int INF = 10000000; int dp[MAXN+10][MAXN+10]; int main(int argc, char* argv[]) { int T, i, j, t1, t2, t3, f1, f2, tmp, n, m; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); fill(dp[0], dp[n+1], INF); dp[0][m] = 0; for(i = 1; i <= n; i++) { scanf("%d%d%d%d%d", &t1, &t2, &t3, &f1, &f2); for(j = m; j >= 0; j--) { dp[i][j] = min(dp[i-1][j]+t2, dp[i][j]); if(j >= f1) { dp[i][j-f1] = min(dp[i-1][j]+t1, dp[i][j-f1]); } tmp = j+f2; if(tmp > m) { tmp = m; } dp[i][tmp] = min(dp[i-1][j]+t3, dp[i][tmp]); } } for(i = 0; i <= n; i++) { for(j = m; j >=0; j--) { printf("%d ", dp[i][j]); } printf("/n"); } printf("%d/n", *min_element(dp[n], dp[n]+m+1)); } return 0; }
然后来个同一种状态表示,但是过程有所不同,从而使代码复杂度增加的(也容易出错):
#include <cstdio> #include <algorithm> #define MAXN 110 #define min(a, b) (a < b ? a : b) using namespace std; const int INF = 10000000; int dp[MAXN+10][MAXN+10]; int main(int argc, char* argv[]) { int T, i, j, t1, t2, t3, f1, f2, tmp, n, m; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); //fill(dp[0], dp[1], 0); //fill(dp[1], dp[n+1], INF); fill(dp[0], dp[n+1], INF); dp[0][m] = 0; for(i = 1; i <= n; i++) { scanf("%d%d%d%d%d", &t1, &t2, &t3, &f1, &f2); for(j = m; j >= 0; j--) { dp[i][j] = dp[i-1][j]+t2; if(j == m) { for(int k = 0; k <= f2 && k <= m; k++) { dp[i][j] = min(dp[i-1][j-k]+t3, dp[i][j]); } } else if(j >= f2){ dp[i][j] = min(dp[i-1][j-f2]+t3, dp[i][j]); } tmp = j+f1; if(tmp <= m) { dp[i][j] = min(dp[i-1][tmp]+t1, dp[i][j]); } } } /*for(i = 0; i <= n; i++) { for(j = m; j >=0; j--) { printf("%d ", dp[i][j]); } printf("/n"); }*/ printf("%d/n", *min_element(dp[n], dp[n]+m+1)); } return 0; }
最后来一种不直观的状态表示(跨第1到第i个栏, 共消耗了j力量):
#include <cstdio> #include <algorithm> #define MAXN 110 #define min(a, b) (a < b ? a : b) using namespace std; const int INF = 10000000; int dp[MAXN+10][MAXN+10]; int main(int argc, char* argv[]) { int T, i, j, t1, t2, t3, f1, f2, tmp, n, m; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); fill(dp[0], dp[1], 0); fill(dp[1], dp[n+1], INF); for(i = 1; i <= n; i++) { scanf("%d%d%d%d%d", &t1, &t2, &t3, &f1, &f2); for(j = m; j >= 0; j--) { dp[i][j] = dp[i-1][j]+t2; if(j >= f1) { dp[i][j] = min(dp[i-1][j-f1]+t1, dp[i][j]); } tmp = j+f2; if(tmp > m) { tmp = m; } dp[i][j] = min(dp[i-1][tmp]+t3, dp[i][j]); } } printf("%d/n", dp[n][m]); } return 0; }
这里最后可以直接用dp[n][m]输出,而其他上面两个代码都不可以。我也表示不解。
不管了,先睡觉去了。。。