[POJ 1062]昂贵的聘礼[最短路][枚举]

题目链接:[POJ 1062]昂贵的聘礼[最短路][枚举]
题意分析:
中文题。注意这句话:

地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。他是一个外来人,所以可以不受这些限制。但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。

也就是说:同一条路径上的任意两个人,等级差不能超过M。
解题思路:
另设一个源点0,让源点0和所有人连边,权值就是物品的原价。
可以兑换的物品间连一条线,权值为优惠后价格。
这样问题就转换成了,从0到1的最短路是多少?
由于每条路径需要满足任意两个人等级差不超过M,所以我们枚举道路上的最小等级,然后每次求一次最短路即可。
个人感受:
被中文题卡题意了= =。细看那句话好像也对,没啥子歧义= =。可怕。
具体代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;

const int INF = 0x7f7f7f7f;
const int MAXN = 111;

struct Edge{
    int to;
    int next;
    ll w;
}edge[MAXN * MAXN];
ll p, rnk[MAXN], dis[MAXN], m;
int head[MAXN], sta[MAXN], cnt = 0;
bool in[MAXN];

void add_edge(int from, int to, ll w)
{
    edge[cnt].w = w;
    edge[cnt].to = to;
    edge[cnt].next = head[from];
    head[from] = cnt++;
}

ll spfa(int s, ll rk) // rk:最小等级
{
    memset(dis, 0x7f, sizeof dis);
    dis[s] = 0;
    int top = 0;
    sta[top++] = s; // 栈模拟spfa
    in[s] = 1;
    while (top)
    {
        int cur = sta[--top]; in[cur] = 0;
        for (int i = head[cur]; ~i; i = edge[i].next)
        {
            Edge &e = edge[i];
            if (rnk[e.to] > rk + m || rnk[e.to] < rk) continue; // 不符合等级要求
            if (dis[e.to] > dis[cur] + e.w)
            {
                dis[e.to] = dis[cur] + e.w;
                if (!in[e.to])
                {
                    sta[top++] = e.to;
                    in[e.to] = 1;
                }
            }
        }
    }
    return dis[1];
}

int main()
{
    int n, x, from;
    ll w;
    scanf("%lld %d", &m, &n);
    memset(head, -1, sizeof head);
    for (int i = 1; i <= n; ++i)
    {
        scanf("%lld %lld %d", &p, &rnk[i], &x);
        add_edge(0, i, p);
        while (x --)
        {
            scanf("%d %lld", &from, &w);
            add_edge(from, i, w);
        }
    }

    ll mind = INF;
    for (int i = 1; i <= n; ++i)
        mind = min(spfa(0, rnk[i]), mind);

    printf("%lld\n", mind);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值