这是我的第一道动态规划题目
其实质是一个 带权的 固定路的 DAG 问题
以下是初学DP解题时容易犯的一些错误和要点
1.状态转移方程 d(i)=min{d(i),d(n-i)+w(i)}
2.求取最短路时解的数组应初始化为无穷大
3.此题必要的初始启动条件(边界条件)(不同的题有不同的条件)就本体而言初始为d[0]=0(0公里时费用为0)
4.条件转移 d(0)->d(n) 答案保留在d[n]处
以下为代码
// NOJ--1401 动态规划 最小乘车费用问题
// 实质是一个带权的完全背包问题
// 实质是一个带权的固定路的DAG问题
#include<iostream>
#include<cstdlib>
#define maxn 1000
#define LOCAL
using namespace std;
const int busnum = 10;
int w[busnum+1];
int n;
int d[maxn];
int main() {
#ifdef LOCAL
freopen("ACMinput.txt", "r", stdin);
//freopen("ACMoutput.txt", "w", stdout);
#endif //LOCAL
for (int i = 1; i <= busnum; i++) cin >> w[i];
cin >> n;
memset(d, 100, sizeof(d)); //初始化为最大值
d[0] = 0; //必要的启动条件
for (int i = 1; i <= busnum; i++) //递推,注意递推顺序
{
for (int j = i; j <= n; j++)
{
if (d[j] > d[j - i] + w[i])
d[j] = d[j - i] + w[i];
}
}
cout << d[n] << endl;
return 0;
}
#include<iostream> #include<cstdlib> #define LOCAL #define maxn 1000 #define min(a,b) ((a)<(b))?(a):(b) using namespace std; const int INF = (int)1e7; const int busnum = 10; int w[busnum + 1]; int n; int d[maxn]; int dp(int tot) //记忆化搜索,递归 { int& ans = d[tot]; if (ans < INF) return ans; for (int j = 1; j <= busnum; j++) if (tot >= j) ans = min(ans, dp(tot - j) + w[j]); return ans; } int main() { #ifdef LOCAL freopen("ACMinput.txt", "r", stdin); //freopen("ACMoutput.txt", "w", stdout); #endif //LOCAL for (int i = 1; i <= 10; i++) cin >> w[i]; cin >> n; for (int i = 1; i < maxn; i++) d[i] = INF; d[0] = 0; //同样不能缺少 cout << dp(n) << endl; return 0; }