D67 最短路+区间约束 Dijkstra 算法 U262078 昂贵的聘礼

D67 最短路+区间约束 Dijkstra 算法 U262078 昂贵的聘礼_哔哩哔哩_bilibili

 

U262078 昂贵的聘礼 - 洛谷

思路

建图技巧:
把物品看做点,分两类连边:

  • 直接购买物品 $i$: 从虚拟源点 0 向 $i$ 连边
  • 用替代品 $t$ 替代物品 $i$:从 $t$ 向 $i$ 连边

                         image

区间约束:
“地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。”
在 Dijkstra 中增加约束条件:$L[v]>=y1 \;\&\&\; L[v]<=y2$
注意:存在比酋长地位等级高的人,所以枚举范围为 $L[1]-m,L[1]+m$

相关板子:

D02【模板】最短路 Dijkstra 算法 P4779 单源最短路径 - 董晓 - 博客园

// 最短路+区间约束 Dijkstra 算法 O(n^3*logn)
#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;

const int N=110,M=10010;
int h[N],to[M],w[M],ne[M],idx;
int n,m,L[N],d[N];

void add(int a,int b,int c){
  to[++idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx;
}
int dijkstra(int y1,int y2){
  memset(d,0x3f,sizeof d);
  priority_queue<pii,vector<pii>,greater<pii> > q; //小根堆
  q.emplace(d[0]=0,0); //从源点0开始
  while(q.size()){
    auto [dd,u]=q.top(); q.pop();
    if(dd>d[u]) continue; //这个u不是第一次出队,不拓展
    for(int i=h[u]; i; i=ne[i]){
      int v=to[i];
      if(L[v]>=y1 && L[v]<=y2){ //区间约束
        if(d[v]>d[u]+w[i]){
          q.emplace(d[v]=d[u]+w[i],v);
        }
      }
    }
  }
  return d[1];
}
int main(){
  cin>>m>>n; //地位等级差距限制、物品总数
  for(int i=1,p,x,t,v; i<=n; i++){
    cin>>p>>L[i]>>x; //物品的价格、主人的地位等级、替代品总数
    add(0,i,p);      //直接购买物品i: 虚拟源点 0 向 i 连边
    for(int j=1; j<=x; j++){
      cin>>t>>v;
      add(t,i,v); //用替代品t替代物品i:从 t 向 i 连边
    }
  }
  
  int ans=1e9;
  for(int i=L[1]-m; i<=L[1]; i++) //包含L[1]的等距区间枚举
    ans=min(ans,dijkstra(i,i+m)); //区间约束的 Dijkstra
  cout<<ans;
}

 

posted @ 2026-02-13 09:44  董晓  阅读(84)  评论(0)    收藏  举报