首先题目的意思很容易理解,都是中文的。 这题是Dijkstra的一个变形, 思路是:
以物品为结点,物品之间的优惠价格为边权值建立临界表,题意就是求图中结点1到其他结点的最短路长度(注意在计算每个结点的时候,加上各节点处物品的价值), 恰好就是探险家经过这个物品买卖途径所需要付出的金钱。用dijkstra算法求出单源最短路径,但是要注意题目中有个等级的约束条件,这就需要枚举各种可能的等级区间。等级区间外的结点不可能被访问。需要注意的问题:
1 有结点等级限制,需要枚举等级
2 把终点的物品价值计入最短路径中去,并且找最小的最短路径输出
3 要注意是单向图,即物品替换关系是单向的
代码:
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <string.h>
#define MAX_N 200
#define MAX_EDGE 10000
#define INF 1000000
using namespace std;
struct Edge
{
int v;
int cost;
int next;
};
Edge edge[MAX_EDGE];
int adj[MAX_N];//adj[i] 代表与结点i 相邻的第一条边, 之后的边由edge[adj[i]].next给出
int dist[MAX_N];
int value[MAX_N];//每个物品的价格
int level[MAX_N];//等级
bool visited[MAX_N];
int M, N;
int edge_num;
struct cmp
{
bool operator() (const int &a, const int &b)
{
return dist[a] > dist[b];
}
};
priority_queue<int, vector<int>, cmp> Q;
void add_edge(int u, int v, int cost)//建立临界表
{
edge[edge_num].v = v;
edge[edge_num].cost = cost;
edge[edge_num].next = adj[u];
adj[u] = edge_num++;
}
void init()
{
scanf("%d %d", &M, &N);
int X;
for(size_t i = 1; i <= N; ++i)
adj[i] = -1;
for(size_t i = 1; i <= N; ++i)
{
scanf("%d %d %d",&value[i], &level[i], &X);
for(size_t j = 0; j < X; ++j)
{
int t, v;
scanf("%d %d", &t, &v);
add_edge(i, t, v);
}
}
}
void Dijkstra(int low, int high)
{
memset(visited, false, sizeof(visited));
for(size_t i = 1; i <= N; ++i)
dist[i] = INF;
for(size_t i = 1; i <= N; ++i)//如果不在等级范围内 则无法交易
{
if(level[i] > high || level[i] < low)
visited[i] = true;
}
dist[1] = 0;
visited[1] = true;
Q.push(1);
while(!Q.empty())
{
int idx = Q.top();
Q.pop();
visited[idx] = true;
for(size_t i = adj[idx]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
int cost = edge[i].cost;
if(!visited[v] && dist[v] > dist[idx] + cost)
{
dist[v] = dist[idx] + cost;
Q.push(v);
}
}
}
}
int main()
{
int ans = INF;
init();
for(int i = level[1] - M; i <= level[1]; ++i)//枚举所有可能的等级范围
{
Dijkstra(i, i + M);
for(size_t j = 1; j <= N; ++j)
{
ans = min(ans, dist[j] + value[j]);
}
}
printf("%d\n", ans);
return 0;
}