带限制的最短路--bzoj1922: [Sdoi2010]大陆争霸

传送门

solution:

带限制的最短路,可以用dijkstra或者spfa实现,只需在更新加入队列的时候稍作改动

dis为到达的最短时间,d为摧毁所有结界时间,则真实时间为两个值取max

要用这个max去更新其他点

dijkstra更新dis的时候,只有当v的结界全部被摧毁才进堆。

同时将所有结界发生器在当前点的点的结界数量--,如果减为0,进堆。

注意只有这个点出队的时候才说明这个点的结界没了,才能将其他点结界数-1

并且进堆的时候要将max值进堆,但不修改dis和 d的值,最后答案也要取max

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#define N 3005
#define M 70005
#define LL long long
using namespace std;
int n,m,cnt,head[N],num[N];
LL dis[N],d[N];
bool vis[N];
priority_queue< pair<LL,int> > q;
vector<int> vec[N];

inline int rd(){
  int x=0,f=1;char c=' ';
  while(c<'0' || c>'9') {if(c=='-')f=-1;c=getchar();}
  while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
  return x*f;
}

struct EDGE{
  int to,nxt,w;
}edge[M];

inline void add(int x,int y,int z){
  edge[++cnt].to=y;
  edge[cnt].nxt=head[x];
  edge[cnt].w=z;
  head[x]=cnt;
}
inline LL max(LL a,LL b) {return a>b?a:b;}

inline void dijkstra(){
  memset(dis,0x3f,sizeof dis);
  dis[1]=0; q.push(make_pair(0,1));
  while(!q.empty()){
    int u=q.top().second; q.pop(); if(vis[u]) continue; vis[u]=1;
    LL mx=max(dis[u],d[u]);
    for(int i=head[u];i;i=edge[i].nxt){
      int v=edge[i].to;
      if(dis[v]>mx+edge[i].w){
        dis[v]=mx+edge[i].w;
        LL tmp=max(dis[v],d[v]);
        if(!num[v]) q.push(make_pair(-tmp,v));
      }
    }
    for(int i=0;i<vec[u].size();i++){
      int v=vec[u][i];
      num[v]--; d[v]=max(d[v],mx);
      LL tmp=max(d[v],dis[v]);
      if(!num[v]) q.push(make_pair(-tmp,v));
    }
  }
}

int main(){
  n=rd(); m=rd();
  for(int i=1;i<=m;i++){
    int x=rd(),y=rd(),z=rd();
    add(x,y,z);
  }
  for(int i=1;i<=n;i++){
    num[i]=rd();
    for(int j=1;j<=num[i];j++){
      int x=rd();
      vec[x].push_back(i);
    }
  }
  dijkstra();
  printf("%lld\n",max(dis[n],d[n]));
  return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值