题意: 题目是中文,字面意思大家应该都看得懂,这里面有两个注意点!!首先,探险家没必要用多样东西去换一样东西,因为不会得到更低的价格。这句话告诉我们探险家只会买一件物品,然后一级级的交换上去直到交换到酋长的物品为止。 其次,地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。(他是一个外来人,所以可以不受这些限制。但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。)这句话其实是有歧义的,真正的意思是,某个地位的人可以和差距它地位为m的人交易,即假设这人地位为 p,他可以和[p-m,p+m]之间的人进行交易!!!
分析: 某个物品用其替代品替代,所以可以在替代品与原物品之间连一条边,边的权值即为优惠价格(先不考虑地位的差距)
然后我们就可以建成一张图,很明显,终点为物品1,起点为除了物品1之外的任何点,找当中路径权值之和最小的。(每次选取每个物品为起点时,就说明你买了这件物品,所以要加上这件物品的价格!)
,
现在考虑地位限制,这里假设限制为0。
另一种情况,现在地位限制为 1.
即一条路径中 | 最小地位-最大地位 | <= 地位限制
我第一次做的时候的想法是在寻找最短路的同时记录路径中最大的地位与最小的地位然后每次到一个点时都判断是否更新最小地位或最大地位,更新后的差值是否会超过地位限制,虽然通过了许多的测试样例,但这里有一种情况就过不去。
我又想把最小地位与最大地位跟着最短路径一起更新,但又会出现一个问题
每次更新一个点时,该是选价值最小的还是选地位差距最小的呢?这难以判断。
所以宣告这种想法破产。。。。(一晚上的青春啊。。。)
然后认真想了想,最终都要想法设法走到物品1,即最短路径中一定包含物品1,那最短路径中的物品1的等级一定包含于[最小地位,最大地位]之间。
假设地位差距为m,那么只要枚举地位差距的区间(此区间一定包含物品1),假设物品1地位为p,这里依次枚举区间的下界,最下界为 p-m,此时的上界为p。最大下界为p,此时上界为p+m。
路径中的点只要在这范围内都合法。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
struct edge{
int from,to,cost;
};
int m,n;
struct peo{
int money, pos; // 第i个物品的价值和等级
}ver[110];
vector<edge> G[110];
void addedge(int from,int to,int cost){
G[from].push_back((edge){from,to,cost});
}
struct hep{
int d,v;
bool operator < (const hep& rhs)const{
return d > rhs.d;
}
};
int dis[110];
int solve(int low){
int ans = 1<<30;
for(int k = 0; k < n; ++k){//依次选每一个物品
for(int j = 0; j < n; ++j)
dis[j] = ver[j].money; //赋值各物品的价格。
priority_queue<hep> que;
que.push((hep){0,k});
while(!que.empty()){
hep x = que.top(); que.pop();
if(dis[x.v] < x.d) continue;
for(int i = 0; i < G[x.v].size(); ++i){
edge& e = G[x.v][i];
if(dis[e.to] > dis[x.v] + e.cost && ver[e.from].pos >= low && ver[e.from].pos <= low+m){
dis[e.to] = dis[e.from]+e.cost;
que.push((hep){dis[e.to],e.to});
}
}
}
ans = min(ans,dis[0]);
}
return ans;
}
int main(){
// freopen("/Users/user/Desktop/1.txt","r",stdin);
cin >> m >> n;
for(int i = 0; i < n; ++i){
cin >> ver[i].money >> ver[i].pos ;
int bian; cin >> bian;
for(int j = 0; j < bian; ++j){
int to,cost; cin >> to >> cost; to--;
addedge(to,i,cost);
}
}
int ans = 1<<30;
for(int i = ver[0].pos-m; i <= ver[0].pos; ++i){
//枚举地位区间
ans = min(ans,solve(i)); // 获得最优解
}
cout << ans << endl;
return 0;
}