
开路:N个城市间有m条单向路,分别从a到b,可以在c处交P路费,也可以直接交R路费。那么问题来了,你的挖掘机怎么开最省钱?
3.4熟练掌握动态规划
状态压缩DP
乍一看可以Dijkstra,实际上的确可以Dijkstra
。不过多了一个预交费的c,所以在遍历的时候多了一维状态,这个维度储存当前走过的城市集合。在Dijkstra的时候,如果走过了c那么就有两个选择,选其中最省的即可;否则没得选。
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#define MAX_N 10 + 1
using namespace std;
class Road
{
public:
int a, b, c, P, R;
Road(int a, int b, int c, int P, int R) : a(a), b(b), c(c), P(P), R(R)
{}
};
class State
{
public:
int current, // 当前位置
cost, // 总花费
S; // 已通过的城市
State(int current, int cost, int S) : current(current), cost(cost), S(S)
{}
bool operator>(const State &other) const
{
return cost > other.cost;
}
};
vector<Road> edge[MAX_N]; // 边的集合,edge[from]
bool visited[MAX_N][1 << MAX_N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int N, m;
cin >> N >> m;
for (int i = 0; i < m; ++i)
{
int a, b, c, P, R;
cin >> a >> b >> c >> P >> R;
edge[a].push_back(Road(a, b, c, P, R));
}
priority_queue<State, vector<State>, greater<State> > que;
que.push(State(1, 0, 1 << 1)); // 现在位于起点1,花费是0,已通过的城市的集合是{1}
memset(visited, 0, sizeof(visited));
State result(-1, -1, -1);
while (!que.empty())
{
State p = que.top();
que.pop();
if (visited[p.current][p.S]) continue;
visited[p.current][p.S] = true;
if (p.current == N)
{
result = p;
break;
}
for (vector<Road>::iterator it = edge[p.current].begin(); it != edge[p.current].end(); ++it)
{
Road e = *it;
int cost = p.cost;
if (p.S & (1 << e.c))
{
cost += min(e.P, e.R);
}
else
{
cost += e.R;
}
que.push(State(e.b, cost, p.S | (1 << e.b)));
}
}
if (result.current == -1)
{
cout << "impossible\n";
}
else
{
cout << result.cost << endl;
}
#ifndef ONLINE_JUDGE
fclose(stdin);
#endif
return 0;
}
| 13569812 | hankcs | 3411 | Accepted | 244K | 16MS | C++ | 2079B | 2014-10-26 22:30:13 |
知识共享署名-非商业性使用-相同方式共享:码农场 » POJ 3411 Paid Roads 题解 《挑战程序设计竞赛》
码农场