DIJ - 昂贵的聘礼 - POJ 1062

DIJ - 昂贵的聘礼 - POJ 1062

题意:

首 行 输 入 等 级 限 制 m , 以 及 物 品 数 量 n 。 首行输入等级限制m,以及物品数量n。 mn

接 着 输 入 n 组 数 据 , 每 组 包 括 非 负 整 数 P , L , X ( X < n ) , 接着输入n组数据,每组包括非负整数P,L,X(X<n), nPLX(X<n)

分 别 代 表 每 件 物 品 的 价 格 P , 级 别 L , 和 该 物 品 的 补 充 物 品 的 数 量 X 。 分别代表每件物品的价格P,级别L,和该物品的补充物品的数量X。 PLX

接 着 输 入 X 行 数 据 , 每 行 包 括 补 充 物 品 的 编 号 I i 和 优 惠 价 格 C i 。 接着输入X行数据,每行包括补充物品的编号I_i和优惠价格C_i。 XIiCi

优 惠 价 格 表 示 , 可 以 通 过 先 购 买 I i 号 物 品 , 则 可 以 C i 的 价 格 购 得 物 品 i 。 优惠价格表示,可以通过先购买I_i号物品,则可以C_i的价格购得物品i。 IiCii

现 需 要 购 买 1 号 物 品 , 可 以 通 过 购 买 一 系 列 的 补 充 物 品 来 使 得 总 花 费 减 少 。 求 最 低 花 费 是 多 少 。 现需要购买1号物品,可以通过购买一系列的补充物品来使得总花费减少。求最低花费是多少。 1使

Sample Input

1 4
10000 3 2
2 8000
3 5000
1000 2 1
4 200
3000 2 1
4 200
50 2 0

Sample Output

5250

数据范围:

1 ≤ N ≤ 100 1 ≤ N ≤ 100 1N100


分析:

设 置 虚 拟 源 点 0 号 点 , 0 号 点 到 其 他 点 之 间 建 立 一 条 有 向 边 , 边 权 为 直 接 购 买 该 点 所 需 的 代 价 。 设置虚拟源点0号点,0号点到其他点之间建立一条有向边,边权为直接购买该点所需的代价。 00

其 他 节 点 之 间 根 据 输 入 , 建 立 有 向 边 , 边 权 为 优 惠 价 格 。 其他节点之间根据输入,建立有向边,边权为优惠价格。

样 例 如 下 图 : 样例如下图:
在这里插入图片描述
问 题 转 化 为 求 从 0 号 点 到 1 号 点 的 最 短 距 离 。 问题转化为求从0号点到1号点的最短距离。 01

以 0 号 点 为 源 点 跑 一 遍 d i j k s t r a 即 可 。 以0号点为源点跑一遍dijkstra即可。 0dijkstra

另 外 , 由 于 等 级 限 制 , 中 途 购 买 到 的 所 有 商 品 的 等 级 与 1 号 商 品 的 等 级 差 不 能 超 过 m , 另外,由于等级限制,中途购买到的所有商品的等级与1号商品的等级差不能超过m, 1m

故 我 们 需 要 枚 举 一 个 等 级 差 的 区 间 , 在 这 个 区 间 内 跑 最 短 路 。 故我们需要枚举一个等级差的区间,在这个区间内跑最短路。

区 间 范 围 是 : [ l e v e l [ 1 ] − m + k , l e v e l [ 1 ] + k ] , 其 中 k ∈ [ 0 , m ] 。 区间范围是:[level[1]-m+k,level[1]+k],其中k∈[0,m]。 [level[1]m+k,level[1]+k]k[0,m]

枚 举 m 个 区 间 , 跑 m 遍 最 短 路 即 可 , 记 录 下 m 遍 最 短 路 求 出 的 最 小 的 代 价 。 枚举m个区间,跑m遍最短路即可,记录下m遍最短路求出的最小的代价。 mmm

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>

using namespace std;

const int N=110,inf=0x3f3f3f3f;

int n,m;
int w[N][N],dis[N];
int level[N];
bool st[N];

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

int main()
{
    cin>>m>>n;
    
    memset(w,0x3f,sizeof w);
    for(int i=0;i<=n;i++) w[i][i]=0;
    
    for(int i=1;i<=n;i++)
    {
        int price,cnt;
        cin>>price>>level[i]>>cnt;
        w[0][i]=min(w[0][i],price);
        while(cnt--)
        {
            int id,cost;
            cin>>id>>cost;
            w[id][i]=min(w[id][i],cost);
        }
    }
    
    int res=inf;
    for(int i=level[1]-m;i<=level[1];i++) res=min(res,dijkstra(i,i+m));
    
    cout<<res<<endl;
    
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值