其他分享
首页 > 其他分享> > acwing 903. 昂贵的聘礼 有约束的最短路

acwing 903. 昂贵的聘礼 有约束的最短路

作者:互联网

题目:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

输入格式

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

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

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

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

输出格式

输出最少需要的金币数。

数据范围

1≤N≤100,
1≤P≤10000,
1≤L,M≤N,
0≤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

题解:

第一次看没读懂题意,以为是相邻两个人的等级不超过m,就可以,没想到竟然是交易的所有人之间不可以超过m
y总的做法是枚举酋长的等级区间。做一个区间范围的dijkstra。
代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n,m,p[N],L[N],dist[N];
typedef pair<int,int>pii;
vector<pii>G[N];
int dijk(int l,int r)
{
    memset(dist,0x3f,sizeof dist);
    dist[0]=p[0];
    priority_queue<pii,vector<pii>,less<pii> > q;
    q.push({dist[0],0});
    while(q.size())
    {
        int u=q.top().second;q.pop();
        for(auto i:G[u])
        {
            int v=i.first,c=i.second;
            if(L[v]<=r&&L[v]>=l&&dist[v]>dist[u]+c)
            {
                dist[v]=dist[u]+c;
                //cout<<v<<"--"<<dist[v]<<endl;
                q.push({dist[v],v});
            }
        }
    }
    return dist[1];
}
int main()
{
    scanf("%d %d",&m,&n);
    for(int i=1;i<=n;i++)
    {
        int num;
        scanf("%d %d %d",&p[i],&L[i],&num);
        G[0].push_back({i,p[i]});
        while(num--)
        {
            int v,c;
            scanf("%d %d",&v,&c);
            G[v].push_back({i,c});
        }
    }
    int res=p[1];
    for (int i = L[1] - m; i <= L[1]; i ++ ) res = min(res, dijk(i, i + m));
    cout<<res<<endl;
}

但是其实我们只用维护区间的最大值和最小值,做一遍最短路就ok了。

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n,m,p[N],L[N],dist[N];
typedef pair<int,int>pii;
struct node
{
    int v,u,l,l1;
    bool operator<(const node& t)const
    {
        return v<t.v;
    }
};
vector<pii>G[N];
void dijk()
{
    memset(dist,0x3f,sizeof dist);
    dist[0]=p[0];
    priority_queue<node> q;
    q.push({dist[0],0,L[1],L[1]});
    while(q.size())
    {
        int u=q.top().u,l=q.top().l,l1=q.top().l1;q.pop();
        for(auto i:G[u])
        {
            int v=i.first,c=i.second;
            if(abs(L[v]-l)<=m&&abs(L[v]-l1)<=m&&dist[v]>dist[u]+c)
            {
                dist[v]=dist[u]+c;
                //cout<<v<<"--"<<dist[v]<<endl;
                q.push({dist[v],v,min(L[v],l),max(L[v],l1)});
            }
        }
    }
    printf("%d",dist[1]);
}
int main()
{
    scanf("%d %d",&m,&n);
    for(int i=1;i<=n;i++)
    {
        int num;
        scanf("%d %d %d",&p[i],&L[i],&num);
        G[0].push_back({i,p[i]});
        while(num--)
        {
            int v,c;
            scanf("%d %d",&v,&c);
            G[v].push_back({i,c});
        }
    }
    dijk();
}

请添加图片描述
请添加图片描述
很显然做一次最短路要来的快的多。

标签:903,dist,int,短路,金币,num,push,scanf,acwing
来源: https://blog.csdn.net/weixin_51423794/article/details/120233619