POJ 1062 昂贵的聘礼 (dijkstra)

题目大意

  • 有n个物品,编号为1…n,每个物品都有三个属性P、L、X(X < N),分别表示物品的价格,等级,替代品数量(即使用其它物品来替代该物品后,只需付出那个物品的价格和替代后的优惠价格即可得到该物品)。
  • 给定m,表示物品之间相差等级不能超过m。假设3个物品,m=1,等级依次为1,2,3。可以用2替代1,却不能使用3替代2,因为1,3之间等级超过m。
  • 求得到物品1的至少需要付出的金币数量

分析

  • 以物品为节点,可替代的物品之间建单向边(比如可用3替代2,则是一条2指向3的单向边),每条边有一个权值v

    v = 起点的价格 - 替换之后的优惠价格 - 终点的价格
    
  • 然后使用dijstra算法求出以节点1开始到各点的最大距离rel即可
  • 答案为 P[1] - rel

代码

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;
#define INF 0x3fffffff
const int maxn = 110;
struct Edge {
    int from , to , v;
    Edge() {}
    Edge(int x , int y , int z) {from = x; to = y; v = z;}
};
struct HeapNode {
    int d , u; //d表示当前节点u距s的距离
    HeapNode() {}
    HeapNode(int x , int y) {d = x; u = y;}
    bool operator < (const HeapNode & rhs) const {
        return d < rhs.d;
    }
};

vector<Edge> edges;
vector<int> G[maxn]; //G[i][j]表示节点i的第j条边在edges中的编号
int P[maxn] , L[maxn] , X[maxn];
int T[maxn][maxn] , V[maxn][maxn];

void init(int n)
{
    edges.clear();
    for(int i = 0; i <= n; i++) G[i].clear();
}
void addEdge(int from , int to , int v) {
    edges.push_back(Edge(from , to , v));
    int m = edges.size();
    G[from].push_back(m - 1);
}
int dis[maxn] , vis[maxn] , maL[maxn] , miL[maxn];
int dijstra(int s , int m , int n) //求最长路
{
    priority_queue<HeapNode> Q;
    for(int i = 0; i <= n; i++) dis[i] = 0;
    memset(vis , 0 , sizeof(vis));
    Q.push(HeapNode(0 , s));
    maL[s] = miL[s] = L[s];
    while(!Q.empty())
    {
        HeapNode cur = Q.top(); Q.pop();
        int u = cur.u;
        if(vis[u]) continue;
        vis[u] = 1;
        for(unsigned i = 0; i < G[u].size(); i++) {
            Edge &e = edges[G[u][i]];
            int tmaL = max(maL[u] , L[e.to]) , tmiL = min(miL[u] , L[e.to]);
            if(tmaL - tmiL <= m && dis[e.to] < dis[u] + e.v) {
                dis[e.to] = dis[u] + e.v;
                //p[e.to] = G[u][i];
                maL[e.to] = tmaL , miL[e.to] = tmiL;
                Q.push(HeapNode(dis[e.to] , e.to));
            }
        }
    }
    int ans = 0;
    for(int i = 1; i <= n; i++) ans = max(ans , dis[i]);
    return ans;
}
int main()
{
    int m , n;
    while(cin >> m >> n)
    {
        init(n);
        for(int i = 1; i <= n; i++) {
            cin >> P[i] >> L[i] >> X[i];
            for(int j = 0; j < X[i]; j++) {
                cin >> T[i][j] >> V[i][j];
            }
        }
        for(int i = 1; i <= n; i++) if(L[i] - L[1] <= m) {
            for(int j = 0; j < X[i]; j++) {
                addEdge(i , T[i][j] , P[i] - V[i][j] - P[T[i][j]]);
            }
        }
        cout << P[1] - dijstra(1 , m , n) << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值