AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 903. $\Large\color{blue}{【算法提高课】昂贵的聘礼(\text{SPFA})}$    原题链接    中等

作者: 作者的头像   incra ,  2022-11-17 14:42:24 ,  所有人可见 ,  阅读 1235


23


<—点个赞吧QwQ

宣传一下算法提高课整理{:target=”_blank”}

年轻的探险家来到了一个印第安部落里。

在那里他和酋长的女儿相爱了,于是便向酋长去求亲。

酋长要他用 $10000$ 个金币作为聘礼才答应把女儿嫁给他。

探险家拿不出这么多金币,便请求酋长降低要求。

酋长说:”嗯,如果你能够替我弄到大祭司的皮袄,我可以只要 $8000$ 金币。如果你能够弄来他的水晶球,那么只要 $5000$ 金币就行了。”

探险家就跑到大祭司那里,向他要求皮袄或水晶球,大祭司要他用金币来换,或者替他弄来其他的东西,他可以降低价格。

探险家于是又跑到其他地方,其他人也提出了类似的要求,或者直接用金币换,或者找到其他东西就可以降低价格。

不过探险家没必要用多样东西去换一样东西,因为不会得到更低的价格。

探险家现在很需要你的帮忙,让他用最少的金币娶到自己的心上人。

另外他要告诉你的是,在这个部落里,等级观念十分森严。

地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。

他是一个外来人,所以可以不受这些限制。

但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。

因此你需要在考虑所有的情况以后给他提供一个最好的方案。

为了方便起见,我们把所有的物品从 $1$ 开始进行编号,酋长的允诺也看作一个物品,并且编号总是 $1$。

每个物品都有对应的价格 $P$,主人的地位等级 $L$,以及一系列的替代品 $T_i$ 和该替代品所对应的”优惠” $V_i$。

如果两人地位等级差距超过了 $M$,就不能”间接交易”。

你必须根据这些数据来计算出探险家最少需要多少金币才能娶到酋长的女儿。

输入格式

输入第一行是两个整数 $M,N$,依次表示地位等级差距限制和物品的总数。

接下来按照编号从小到大依次给出了 $N$ 个物品的描述。

每个物品的描述开头是三个非负整数 $P、L、X$,依次表示该物品的价格、主人的地位等级和替代品总数。

接下来 $X$ 行每行包括两个整数 $T$ 和 $V$,分别表示替代品的编号和”优惠价格”。

输出格式

输出最少需要的金币数。

数据范围

$1 \\le N \\le 100$,
$1 \\le P \\le 10000$,
$1 \\le L, M \\le N$,
$0 \\le X < N$

输入格式

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

输出格式

5250

思路

我们用一条$(u,v,w)$得边表示第$v$件物品可以由第$u$件物品加上$w$买到。
那我们万一要直接买怎么办?
我们直接建一个超级源点$0$,把它和所有物品连一条边,最后输出$0\sim 1$的最短路即可。
没了吗?
还有!地位差咋办?
因为我们一定要到$1$号节点,所以买卖的等级必须包含$1$号点。
没了。

代码

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N = 110,M = 10010,INF = 0x3f3f3f3f;
int m,n;
int h[N],e[M],w[M],ne[M],idx;
int L[N];
int dist[N];
bool st[N];
void add (int a,int b,int c) {
    e[idx] = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a] = idx++;
}
int spfa (int l,int r) {
    memset (dist,0x3f,sizeof (dist));
    memset (st,false,sizeof (st));
    dist[0] = 0;
    queue <int> q;
    q.push (0);
    while (!q.empty ()) {
        int t = q.front ();
        q.pop ();
        st[t] = false;
        for (int i = h[t];~i;i = ne[i]) {
            int j = e[i];
            if (l <= L[j] && L[j] <= r && dist[j] > dist[t] + w[i]) {
                dist[j] = dist[t]+w[i];
                if (!st[j]) {
                    q.push (j);
                    st[j] = true;
                }
            }
        }
    }
    return dist[1];
}
int main () {
    memset (h,-1,sizeof (h));
    cin >> m >> n;
    for (int i = 1;i <= n;i++) {
        int x,k;
        cin >> x >> L[i] >> k;
        add (0,i,x);
        while (k--) {
            int w;
            cin >> x >> w;
            add (x,i,w);
        }
    }
    int ans = INF;
    for (int i = L[1] - m;i <= L[1];i++) ans = min (ans,spfa (i,i + m));
    cout << ans << endl;
    return 0;
}

4 评论


用户头像
已退役   2023-06-02 20:54      1    踩      回复

spfa时间复杂度不好吧

用户头像
incra   2023-06-03 07:27      1    踩      回复

不卡的话还不错

用户头像
user.banned   2023-12-27 13:40    回复了 incra 的评论      1    踩      回复

好的我要卡SPFA去了,把你的SPFA卡死(


用户头像
懵逼自动机   2023-04-04 22:10      1    踩      回复

Orz


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息