poj1062
题意:每个人都有一个物品,对应一定的钱数,想要得到此物品可以直接出钱,也可以通过用其他人的物品并添加一些钱来交换,问要得到酋长的物品最少需要多少钱?另外,每个人都有一个等级,要求和你交易的人中不能有任何两人的等级相差m以上。
分析:我们可以把本题理解为,我们要买一号物品,而一个物品的一部分价值可以转化为别的物品,我们通过购买别的物品和加钱来购买获得一号物品。所以我们可以把需要加的钱数作为该物品到别的物品的一条边,走过这条边,我们要花一些钱,然后我们只需要购买现在所在结点的物品即可。这样就把问题转化为最短路问题,用dijkstra就可以了。
本题还有个等级制度的问题。我们可以每次枚举一个宽为m的等级区间,忽略不在区间内的点,进行dijkstra。
我wrong answer是因为第一次没处理起始点不在枚举的区间内的情况。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn = 101, inf = 1000000000; struct Item { int p, l; } item[maxn]; struct Edge { int v, w; Edge() { } Edge(int vv, int ww) : v(vv), w(ww) { } } e[maxn * maxn]; int map[maxn], level[maxn], levelnum = 0, dist[maxn]; int n, m; bool vis[maxn]; void dijkstra(int floor) { int best = 0, besti = 0; int d[maxn]; for (int i = 0; i <n; i++) { d[i] = inf; vis[i] = false; } d[0] = 0; while (besti != -1) { vis[besti] = true; for (int i = map[besti]; i < map[besti + 1]; i++) { if (d[e[i].v] > best + e[i].w && item[e[i].v].l >= floor && item[e[i].v].l <= floor + m) { d[e[i].v] = best + e[i].w; } } best = inf; besti = -1; for (int i = 0; i < n; i++) if (!vis[i] && d[i] < best) { best = d[i]; besti = i; } } for (int i = 0; i < n; i++) if (dist[i] > d[i]) dist[i] = d[i]; } int main() { //freopen("D:\\t.txt", "r", stdin); scanf("%d%d", &m, &n); for (int i = 0; i < n; i++) dist[i] = inf; map[0] = 0; for (int i = 0; i < n; i++) { int temp; scanf("%d%d%d", &item[i].p, &item[i].l, &temp); level[levelnum++] = item[i].l; map[i + 1] = map[i] + temp; for (int j = 0; j < temp; j++) { int a, b; scanf("%d%d", &a, &b); a--; e[map[i] + j] = Edge(a, b); } } sort(level, level + levelnum); levelnum = unique(level, level + levelnum) - level; for (int i = 0; i < levelnum; i++) if (item[0].l >= level[i] && item[0].l <= level[i] + m) dijkstra(level[i]); int ans = inf; for (int i = 0; i < n; i++) if (ans > dist[i] + item[i].p) ans = dist[i] + item[i].p; printf("%d\n", ans); return 0; }