POJ 1062 昂贵的聘礼

题目链接: [kuangbin带你飞]专题四 最短路练习 M - 昂贵的聘礼

题意

年轻的探险家来到了一个印第安部落里。在那里他和酋长的女儿相爱了,于是便向酋长去求亲。酋长要他用10000个金币作为聘礼才答应把女儿嫁给他。探险家拿不出这
么多金币,便请求酋长降低要求。酋长说:”嗯,如果你能够替我弄到大祭司的皮袄,我可以只要8000金币。如果你能够弄来他的水晶球,那么只要5000金币就行了。”
探险家就跑到大祭司那里,向他要求皮袄或水晶球,大祭司要他用金币来换,或者替他弄来其他的东西,他可以降低价格。探险家于是又跑到其他地方,其他人也提出了类似的要
求,或者直接用金币换,或者找到其他东西就可以降低价格。不过探险家没必要用多样东西去换一样东西,因为不会得到更低的价格。探险家现在很需要你的帮忙,让他用最少的
金币娶到自己的心上人。另外他要告诉你的是,在这个部落里,等级观念十分森严。地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。他是一个外来
人,所以可以不受这些限制。但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。因此你需要在考虑所
有的情况以后给他提供一个最好的方案。
为了方便起见,我们把所有的物品从1开始进行编号,酋长的允诺也看作一个物品,并且编号总是1。每个物品都有对应的价格P,主人的地位等级L,以及一系列的替代品Ti
和该替代品所对应的”优惠”Vi。如果两人地位等级差距超过了M,就不能”间接交易”。你必须根据这些数据来计算出探险家最少需要多少金币才能娶到酋长的女儿。

思路

将两两物品之间的交易详情看做边,每个物品看做点,可用最短路求解,但是题目里等级的设置让问题变得麻烦了些。
题目关键的地方是:不仅是交易的双方等级不能差距M,而是所有有过交易的物品两两之间等级都不能差距M。
因为最终都要交换到第一件物品,也就是酋长的承诺,所以由酋长的等级,和M可以产生一个等级区间,等级在此区间内的物品才可以交换。所以对等级区间进行枚举,求最短路
便可解决此问题。

代码

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 209;
int v[N][N] = {};
int d[N];
bool vis[N] = {};
int p[N], l[N], q[N];
bool f[N] = {};

int dijkstra(int n)
{
    memset(vis, 0, sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        d[i] = v[0][i];
    }
    d[0] = 0;
    vis[0] = 1;
    for(int i=1; i<=n; i++)
    {
        int x = 0, mmin = 0x3f3f3f3f;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i] && f[i] && mmin > d[i])
                mmin = d[x = i];
        }
        vis[x] = 1;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i] && f[i] && d[i] > d[x] + v[x][i])
            {
                d[i] = d[x] + v[x][i];
            }
        }
    }
    return d[1];
}

int main()
{
    int n, m;
    cin>>m>>n;
    memset(v, 0x3f3f3f3f, sizeof(v));
    for(int i=1;i<=n;i++)
    {
        int t;
        cin>>p[i]>>l[i]>>t;
        v[0][i] = p[i];
        for(int j=0;j<t;j++)
        {
            int a, b;
            cin>>a>>b;
            v[a][i] = b;
        }
    }
    int ans = 0x3f3f3f3f;
    for(int i=0; i<=m; i++)
    {
        memset(f, 0, sizeof(f));
        for(int j=1; j<=n; j++)
        {
            if(l[j] >= l[1]-m+i && l[j] <= l[1]+i)
                f[j] = 1;
        }
        ans = min(ans, dijkstra(n));
    }
    cout<<ans<<endl;
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!