POJ 1062 priority_queue + Dijkstra (临界表) 实现

  首先题目的意思很容易理解,都是中文的。 这题是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;
}


 

你可能感兴趣的:(算法,ACM,poj,dijkstra)