昂贵的聘礼

昂贵的聘礼

题目来源:http://bailian.openjudge.cn/practice/1062/

  • 解题思路:

    • 假设冒险家自身是第0号物品,可以将这道题目理解为经过一系列的物品的交换,花费最少的金币换得酋长的1号物品。
      -将其看作图论,建图的时候,每次遇到一个物品及其原价,可以设置0号物品到该物品的距离为该物品的价值。即表明冒险家直接购买物品需要花费的金币。
    • 对于某个物品的替代品,可以设置为替代品的编号到原物品编号之间的花费为“优惠价格”,无论经过多少次交换,最后必须和酋长进行交换,而酋长对冒险家交换过的物品等级有限制,假设酋长的地位为Q,可以忍受的等级差距为M,那么就可以枚举等级差距为M的等级范围。即[Q-M, Q],[Q-M+1, Q+1]…[Q, Q+M]。
    • 将所有等级限制范围内可以交换花费的最小金币求取最小值,即为最少花费的金币。
  • AC代码

#include <vector>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <climits>
#include <queue>
#include <cstdio>

using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef const int CI;

struct Gift {
	int level;
	int value;
	Gift(int l = 0, int v = 0) :level(l), value(v) {};
};

struct Edge {
	int from, to;
	int dis;
	Edge(int f, int t, int d) :from(f), to(t), dis(d) {}
	bool operator<(const Edge& e)const { return this->dis > e.dis; };
};

// dijkstra 算法,low和high分别表示等级范围
int solution(const VVI& graph, const vector<Gift>& gift, CI low, CI high) {
	VI dis(graph.size(), INT_MAX);
	dis[0] = 0;
	priority_queue<Edge> myQueue;
    // 每次加入边的时候考虑等级差距
	for (int i = 1; i < graph.size(); ++i){
		if (gift[i].level >= low&&gift[i].level <= high)
			dis[i] = graph[0][i];
		else
			dis[i] = INT_MAX;
		myQueue.push(Edge(0, i, dis[i]));
	}
	VI visit(graph.size(), 0);
	visit[0] = 1;
	while (!myQueue.empty()) {
		Edge e = myQueue.top();
		myQueue.pop();
		if (visit[e.to] == 1)
			continue;
		visit[e.to] = 1;
		dis[e.to] = e.dis;
		for (int j = 1; j < graph.size(); ++j) {
            // 每次加入边的时候考虑等级差距
			if (visit[j] == 0 && gift[j].level >= low&&gift[j].level <= high&&dis[e.to] < dis[j] - graph[e.to][j])
				myQueue.push(Edge(e.to, j, dis[e.to] + graph[e.to][j]));
		}
	}
	return dis[1];
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int M, N;
	while (cin >> M >> N) {
		vector<Gift> gift(N + 1);
		
		VVI graph(N + 1, VI(N + 1, INT_MAX));
		for (int i = 0; i < N + 1; ++i)
			graph[i][i] = 0;
		
		for (int i = 1; i <= N; ++i) {
			int alter;
			cin >> gift[i].value >> gift[i].level >> alter;
			graph[0][i] = gift[i].value;
			for (int j = 0; j < alter; ++j) {
				int x, y;
				cin >> x >> y;
				graph[x][i] = y;
			}
		}
		CI L = gift[1].level;
		int ans = INT_MAX;
		for (int i = 0; i <= M; ++i) {
			int tmp = solution(graph, gift,  L - i, L - i + M);
			ans = min(ans, tmp);
		}
		printf("%d\n", ans);
	}
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值