昂贵的聘礼(最短路、建图)

昂贵的聘礼

题意

有若干物品,这些物品都有一个价格,还有拥有者的等级(目标点的等级最高),然后还会有若干替代品以及优惠后的价格。每个物品购买的时候最多只能使用一种它的替代品。交换的时候,参与交换的所有所有者的等级差有一个上限。问,交换到目标物品,最少需要多少钱。

做法

可以考虑这样建图,每件物品的替代品可以连一条通向该物品的有向边,边权为优惠后的价格。并且设立一个虚拟源点,连向所有物品,边权为这些物品的价格。问题就转化成了,从虚拟源点到目标点的最短路。下面考虑等级差的限制问题,因为目标点的等级已经确定,所以可以遍历满足要求的下限,对每个等级区间求一遍最短路,然后求最小值。在求最短路的过程中,只有在等级区间范围内的点才可以更新,不在范围内的点不能更新。

代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 110, inf = 0x3f3f3f3f;

int n,m,k;
int g[N][N];
int rk[N], dist[N];
bool st[N];

int dijkstra(int down, int up)
{
    
    
    memset(dist,0x3f,sizeof(dist));
    memset(st,false,sizeof(st));
    dist[0] = 0;
    for(int i=0;i<=n;i++){
    
    
        int t = -1;
        for(int j=0;j<=n;j++){
    
    
            if(!st[j]&&(t==-1||dist[t]>dist[j])){
    
    
                t = j;
            }
        }
        st[t] = true;
        for(int j=1;j<=n;j++){
    
    
            if(rk[j]>=down&&rk[j]<=up){
    
    
                dist[j] = min(dist[j], dist[t]+g[t][j]);
            }
        }
    }
    return dist[1];
}

int main()
{
    
    
    cin >> k >> n;
    memset(g,0x3f,sizeof(g));
    for(int i=1;i<=n;i++) g[i][i] = 0;
    for(int i=1;i<=n;i++){
    
    
        int price, level, cnt;
        cin >> price >> level >> cnt;
        rk[i] = level;
        g[0][i] = min(g[0][i], price);
        for(int j=0;j<cnt;j++){
    
    
            int id, c;
            cin >> id >> c;
            g[id][i] = min(g[id][i], c);
        }
    }
    int res = inf;
    for(int i=rk[1]-k;i<=rk[1];i++) res = min(res, dijkstra(i, i+k));
    cout << res << endl;
    return 0;
}

收获

这道题引入了一个限制,这个限制是有一个属性,每个点都有一个值,路径上所有点的这个属性差有一个上限。这种题就是枚举满足这个限制的所有区间,在每个区间求一遍最短路。这与二维最短路问题有区别,二维最短路问题是有两种边权,一种边权求最短路,另一种边权的路径长度满足一个限制。二维最短路问题在后面进行详细叙述。

猜你喜欢

转载自blog.csdn.net/weixin_43634220/article/details/108604225