这道题实际上是单源最短路径问题,每条边(从一个物品到替换它的物品之间)都有一个权值,即cost。问题是求从第一个物品到其他所有物品的最低开销,这个开销除了路径总cost外还得包含这个物品的价值(因为这个物品是最终替代第一个物品的物品)。
明白了上述这些后,自然而然的想法就是应用最短路径算法,比如Dijkstra,SPFA或是Bellman-Ford。
这个问题的有意思的地方在于它还对可选的物品有个限制,即从第一个物品到每个物品的路径上的物品的Level之差必须在M以内。一个简单的处理方法就是做枚举。假设第一个物品的Level是L(准确的说是拿物品的人的Level,而第一个物品是必须“交易”的,无论选第一个物品还是选它的替代品)。那么Level的最低值low范围为[L - M, L]。相应的Level最高值high为low + M。所以需要对low,high的限定范围做个枚举,跑这个多次单源最短路径,然后求出所有这些中的最小开销。
事实证明Dijkstra是个非常高效的方法,即使在实现得很烂的情况下(如本题的实现没有用priority_queue,所以每步选min的时间都是O(N))。时间仍然是0ms。
可以参见http://poj.org/showmessage?message_id=183977。代码实现得很清楚。
1062 | Accepted | 168K | 0MS | C++ | 3031B |
/*
ID: thestor1
LANG: C++
TASK: poj1062
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>
using namespace std;
class Substitute
{
public:
int T, V;
Substitute() {}
Substitute(int T, int V) : T(T), V(V) {}
};
class Item
{
public:
int P, L, minP;
vector<Substitute> substitutes;
Item() : minP(-1) {}
Item(int P, int L) : P(P), L(L), minP(-1) {}
};
int dfs(vector<Item> &items, int t, int low, int high, const int M)
{
if (items[t].minP >= 0)
{
return items[t].minP;
}
int minP = items[t].P;
for (int i = 0; i < items[t].substitutes.size(); ++i)
{
if (low <= items[items[t].substitutes[i].T].L && items[items[t].substitutes[i].T].L <= high)
{
// substitutes[i].T, substitutes[i].V
int price = dfs(items, items[t].substitutes[i].T, max(low, items[items[t].substitutes[i].T].L - M), min(high, items[items[t].substitutes[i].T].L + M), M);
if (price + items[t].substitutes[i].V < minP)
{
minP = price + items[t].substitutes[i].V;
}
}
}
items[t].minP = minP;
return minP;
}
int dijkstra(vector<Item> &items, const int low, const int high, vector<bool> &visited, vector<int> &dis)
{
int N = items.size();
for (int i = 0; i < N; ++i)
{
if (items[i].L < low || items[i].L > high)
{
visited[i] = true;
}
else
{
visited[i] = false;
}
dis[i] = INT_MAX;
}
dis[0] = 0;
for (int i = 0; i < N; ++i)
{
int mindis = INT_MAX, minu = -1;
for (int j = 0; j < N; ++j)
{
if (!visited[j] && dis[j] < mindis)
{
mindis = dis[j];
minu = j;
}
}
if (mindis == INT_MAX)
{
break;
}
visited[minu] = true;
for (int j = 0; j < items[minu].substitutes.size(); ++j)
{
Substitute substitute = items[minu].substitutes[j];
if (!visited[substitute.T] && mindis < INT_MAX - substitute.V && mindis + substitute.V < dis[substitute.T])
{
dis[substitute.T] = mindis + substitute.V;
}
}
}
int minP = INT_MAX;
for (int i = 0; i < N; ++i)
{
if (dis[i] < INT_MAX - items[i].P && dis[i] + items[i].P < minP)
{
minP = dis[i] + items[i].P;
}
}
return minP;
}
int main()
{
int M, N;
scanf("%d%d", &M, &N);
vector<Item> items(N);
int X, T, V;
for (int i = 0; i < N; ++i)
{
scanf("%d%d%d", &items[i].P, &items[i].L, &X);
for (int j = 0; j < X; ++j)
{
scanf("%d%d", &T, &V);
T--;
items[i].substitutes.push_back(Substitute(T, V));
}
}
int minP = INT_MAX;
vector<bool> visited(N);
vector<int> dis(N);
for (int low = items[0].L - M; low <= items[0].L; ++low)
{
int high = low + M;
int price = dijkstra(items, low, high, visited, dis);
if (price < minP)
{
minP = price;
}
}
printf("%d\n", minP);
return 0;
}