http://poj.org/problem?id=2355
要点:
- 插点更新的思路
- dp的初态设定要重视
- dp的更新顺序有时是不影响的。
一维插点求单源最短路(?
- 在s与e间进行查找
- 如果中间经停一个车站可以一次到达终点的话,就尝试用到达这个经停加上最后一站的费用进行更新。
while循环寻找可以一步到达本次终点的节点。
for (int i = s+1; i <= e; i++)
{
int j = s;
while (dist[i] - dist[j] > l[3]) j++;
for (; j < i; j++)
dp[i] = min(dp[j] + cost(dist[i]-dist[j]), dp[i]);
}
最初以为这里涉及二维变一维导致的覆盖顺序问题。但把两段代码放在一起说明等价时,发现前一个while循环中的l[3]打成了c[3]。低级错误
但实际上这步操作可以利用倒序实现:
for (int i = s+1; i <= e; i++)
{
for (int j = i-1; j >= s; j--)
if (dist[i]-dist[j] > l[3])
break;
else
dp[i] = min(dp[j] + cost(dist[i]-dist[j]), dp[i]);
}
另外题中需要注意两个初态:动态规划的初始状态一定要想明白!
距离的初态为0,dp初态为0。
#include <bits/stdc++.h>
using namespace std;
int l[4], c[4];
int cost(int km)
{
if (km <= l[1])
return c[1];
else if (km <= l[2])
return c[2];
else if (km <= l[3])
return c[3];
else return 1e9+100;
}
int main()
{
#ifdef _LOC_
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
cin >> l[1] >> l[2] >> l[3] >> c[1] >> c[2] >> c[3];
int n, s, e;
cin >> n >> s >> e;
if (s > e) swap(s, e);
int dist[10020];
int dp[10020]; memset(dp, 0x3f, sizeof dp);
dp[s] = 0; dist[1] = 0; //初态
for (int i = 2; i <= n; i++)
cin >> dist[i];
for (int i = s+1; i <= e; i++)
{
for (int j = i-1; j >= s; j--)
if (dist[i]-dist[j] > l[3])
break;
else
dp[i] = min(dp[j] + cost(dist[i]-dist[j]), dp[i]);
}
cout << dp[e];
#ifdef _LOC_
fclose(stdin);
fclose(stdout);
#endif
return 0;
}