玲珑 2018-02-17
Description
问题:链接
更多的测试用例:POJ DISCUSS
思路
这道题的关键点有两个:图的构建与物品能进行交换的等级区间。
对于前一个问题,需要以探险家作为起始点,设其编号为0,暂且计各物品编号为顶点编号,物品为各顶点,由于探险家可以用金币买各个物品,所以 0 点可以直接到达其余各点,边的权为购买该物品的金币数;而物品 i 与物品 j 间可能进行交换,所以让 i -> j 表示用“物品 j + 物品 i 优惠后的价格 = 物品 i” 。而原问题—— ”探险家化最少的金币买到酋长的诺言“ 也就转换成了求 0 点 到 1 点的最短路。
原问题在交换物品时还有另外一个要求:两两交换的物品的地位不能相差 M 且所有经交换的物品的地位不能相差 M 。顺着这个思路,我们一开始可能会以酋长为最高等级 level,取等级在区间 [ level - M, level ] 中的物品进行交换,而剔除区间之外的物品。但是忽略了一个问题:酋长可能不是最高等级! 这个问题也很好理解,比如酋长的爸爸、酋长的爷爷...等等的等级就可能比酋长还高。那么就会想把区间扩展到 [ level - M, level + M ] 。但是在这个区间中的两件物品相差可能会超过 M,比如等级为 level - M 的物品与 level + 1 的物品它们的等级差距为 M+1 。那么我们就需要从 [ level - M, level ] 开始到 [lev, lev + M ] 结束,穷举区间,记录最小的最短路。


#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
int M, N; //最大等级差距与物品数
const int MAX_N = ;
struct Edge{
int to;
int cost;
Edge(int tt, int cc) : to(tt), cost(cc) {}
};
vector<Edge> G[MAX_N];
void addEdge (const int& u, const int& v, const int& w) {
G[u].push_back(Edge(v, w));
}
struct Node{
int id;
int cost;
friend bool operator < (const Node& a, const Node& b) {
return a.cost > b.cost;
}
}dis[MAX_N];
bool visit[MAX_N];
int level[MAX_N];
bool outlevel[MAX_N];
void dijkstra(const int& s) {
for (int i = ; i <= N; i++) dis[i].id = i, dis[i].cost = INF;
dis[].id = , dis[].cost = ;
for (int i = ; i <= N; i++) visit[i] = false;
priority_queue<Node> pQueue;
pQueue.push(dis[]);
while(!pQueue.empty()) {
int u = pQueue.top().id; pQueue.pop();
if (visit[u]) continue;
visit[u] = true;
for (int j = ; j < G[u].size(); j++) {
int v = G[u][j].to;
int cost = G[u][j].cost;
if (!outlevel[v] && dis[v].cost > dis[u].cost + cost ) {
dis[v].cost = dis[u].cost + cost;
pQueue.push(dis[v]);
}
}
}
}
int main(void) {
cin >> M >> N;
for (int i = ; i <= N; i++) G[i].clear();
for (int i = ; i <= N; i++) {
int P, L, X;
cin >> P >> L >> X;
level[i] = L;
addEdge(, i, P); //探险家可直接买物品
//以物抵金币
for (int j = ; j <= X; j++) {
int num, cost;
cin >> num >> cost;
addEdge (num, i, cost);
}
}
//枚举每一个等级作为最小等级,在可交换的等级区间内求最短路
int ans = INF;
for (int i = ; i <= N; i++) {
//去除不可交换的等级区间内的物品
for (int j = ; j <= N; ++j) outlevel[j] = false;
int min_level = level[i];
for (int j = ; j <= N; j++) {
if (level[j] < min_level || min_level + M < level[j] )
outlevel[j] = true; //第j个物品不可用于交换
}
dijkstra();
ans = min(ans, dis[].cost);
}
cout << ans << endl;
return ;
}View Code