昂贵的聘礼 POJ - 1062 (最短路专题)
题目描述
会长东东想娶酋长的女儿,但酋长要求他给一定数额金钱的聘礼。除了金钱外,酋长也允许用部落里其他人的某物品加上一点钱作为聘礼。而其他人的物品也可以通过指定的另外一些人的某物品加上一些金钱获得。但是部落里的每个人有一个等级。整个交易过程涉及的人的等级只能在一个限定的差值内。问会长东东最少需要多少金钱才能娶到酋长女儿。假定每个人只有一个物品。
Input
输入第一行是两个整数M,N(1 <= N <= 100),依次表示地位等级差距限制和物品的总数。接下来按照编号从小到大依次给出了N个物品的描述。每个物品的描述开头是三个非负整数P、L、X(X < N),依次表示该物品的价格、主人的地位等级和替代品总数。接下来X行每行包括两个整数T和V,分别表示替代品的编号和"优惠价格"。
Output
输出最少需要的金币数。
解题思路:先抛去等级,我们可以对所有物品进行建图。
即以0作为超级源点,与每样物品进行建边,边的权值就是该物品的价格,因此两点间的距离就是由一点的物品变成另 一点的物品的代价。因此要求最小代价,也就是求 从0到1的最短距离。
因为有等级限制,因此我们可以枚举每个区间的从 0 到 1 的最短距离。在这些最短距离中求最短距离。
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define ll long long
#define MOD 998244353
#define INF 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int NUM = 105; //点数
struct edge{
int from,to,w;
edge(int a,int b,int c){from=a;to=b;w=c;}
};
vector<edge>e[NUM];
int level[NUM];
int m,n;
int Dijkstra(int l,int r)
{
int dis[NUM];
bool vis[NUM];
for(int i=0;i<=n;i++){
dis[i]=INF;
vis[i]=false;
}
dis[0]=0;
queue<int>Q;
Q.push(0);
while(!Q.empty())
{
int u=Q.front();
Q.pop();
//if(vis[u])continue;
vis[u]=0;
for(int i=0;i<e[u].size();i++){
int v=e[u][i].to,w=e[u][i].w;
if(level[v]<l||level[v]>r)continue; //等级不符合此次枚举
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
//cout<<u<<" "<<v<<" "<<dis[v]<<endl;
Q.push(v);
}
}
}
return dis[1];
}
int main()
{
scanf("%d %d",&m,&n);
for(int i=1;i<=n;i++){
int a,l,x;
scanf("%d %d %d",&a,&l,&x);
e[0].push_back(edge(0,i,a));
level[i]=l;
for(int j=1;j<=x;j++){
int b,c;
scanf("%d %d",&b,&c);
e[b].push_back(edge(b,i,c));
}
}
int ans=INF;
for(int i=level[1]-m;i<=level[1];i++){ //所有有可能的区间的枚举
ans=min(Dijkstra(i,i+m),ans);
}
cout<<ans;
return 0;
}
越自律,越自由