POJ1062昂贵的聘礼(Dijkstra+限制)

来源:互联网 发布:base64 上传七牛 java 编辑:程序博客网 时间:2024/06/06 05:52

分析:

        现在我们假设没有等级限制,且有A,B,C共3种商品且A,B,C的原价分别为10000,9000,8000且A可以由B物品加上优惠价7000换取,A还可以由C物品加上优惠价1000换取. 我们在纸上把这个图画出来,然后添加一个0号节点.

        从0号节点到A,B,C的有向边花费为A,B,C 3物品直接购买(不用物品+优惠价)的价格.比如从0到A花费10000.

        然后比如A物品 可以用B物品+7000来换取,那么从B到A物品有一条有向边,花费为7000.从C到A有一条花费1000的有向边.

        其实上面建立的图从0号节点到A或B或C的一条路的总花费就是购买A,B,C物品的一种可能总花费了.

        那么我们想要购买A物品的最小花费是多少呢? 明显可以看出从0号节点到A物品的最短路径就是最小花费了.

最晦涩难懂就是这个等级限制了。本来想拿这道题入门写一下Dj算法,没想到被这个限制折磨好久~。

等级限制:

假设M=1,那么a,b,c,d等级分别为 1, 2, 3,4。如果从b那里买了,然后可以去c那里买,但是不可以去d那里买了,因为d和b相差2,如果前面已经去c那里买了,a也不能买了,因为ac相差2。

所以我们只需枚举所有的顶点的等级,然后求若干次最短路,每次只访问等级在[x,x+M]范围内的点,最后输出d[1](到他丈母大爷那里买)的最小值。

#include<iostream>#include<vector>#include<cstdio>#include<queue>#include<cstring>#include<algorithm>#include<string>#include<functional>using namespace std;#define INF 0x3f3f3f3fstruct edge{int to, cost;};vector<edge>G[105];//人家只想练练用邻接表的dj算法,谁知道这是一道浙江省赛选拔题typedef pair<int, int>P;int M, N;int level[105];int d[105];void dijskra(int s,int min_value){priority_queue<P, vector<P>, greater<P> >que;fill(d, d + N + 1, INF);d[s] = 0;que.push(P(0, s));while (que.size()){P p = que.top(); que.pop();int v = p.second;if (d[v] < p.first)continue;//此时在其他点中更新了,也就是用过了。for (int i = 0; i < G[v].size(); i++){   edge e = G[v][i];if (d[e.to] > d[v] + e.cost){if (v == 0 || (level[v]>=min_value&&level[v]<=min_value+M)&& (level[e.to] >= min_value&&level[e.to] <= min_value + M)){d[e.to] = d[v] + e.cost;que.push(P(d[e.to], e.to));}}}}}int main(){while (cin >> M >> N){for (int i = 1; i <= N; i++){int P, X;cin >> P >> level[i] >> X;edge tmp0 = { i,P };G[0].push_back(tmp0);while (X--){int T, V;cin >> T >> V;edge tmp = { i,V };G[T].push_back(tmp);}}int ans = INF;level[N + 1] = INF;//方便去重for (int i = 1; i <= N; i++){if (level[i] == level[i + 1])continue;//简单去重吧,发现排序后再去重,时间反倒增加了dijskra(0, level[i]);ans = min(ans, d[1]);}cout << ans << endl;}}