zoj 3794 spfa


给定n个点,m条有向边,邮箱容量c。

起点在1,终点在n,开始邮箱满油。

下面m行表示起点终点和这条边的耗油量(就是长度)

再下面给出一个数字m表示有P个加油站,可以免费加满油。

下面一行P个数字表示加油站的点标。

再下面一个整数Q

下面Q行 u v 表示在u点有销售站,可以卖掉邮箱里的任意数量的油,每以单位v元。

问跑到终点能获得最多多少元。

再华丽的描述外表也掩盖不住水题的性质。

这个题的下手点在 :   卖油只能卖1次,假设在i点处卖油 , 那么我应该要知道2个量,一个是现在油箱里还有多少油,一个是到达终点

还需要多少油。差值就可以卖了。  

最大值  1 ,枚举  2 , 满足i处油箱有最多 ; i到n耗油最少。 那么:

正向边   : 求个每个点的最大剩余油量 dist1[i],

反向边   : 求每个点距离终点的最少还需的油量   dist2[i]。

然后枚举一下每个销售点即可,( dist1[i] - dist2[i] ) * wi  。


const   int  maxn = 1008 ;
const   int  maxm = 100008 ;
const   int  inf = 2000000000  ;

struct  Graph{
        int  lis[maxn]  ;
        int  id ;
        struct  Edge{
                int v ;
                int w ;
                int next ;
        }e[maxm];
        void  Clear(){
              memset(lis , -1 , sizeof(lis)) ;
              id = 0 ;
        }
        void  add(int u, int v , int w){
              e[id].v = v  ;
              e[id].w = w  ;
              e[id].next = lis[u] ;
              lis[u] = id++ ;
        }
};
Graph g1 , g2 ;
int   n , m , c ;
bool  fuel[maxn]  ;
int   sell[maxn][2]  ;
bool  in[maxn]  ;
int   dist1[maxn]  , dist2[maxn]  ;

void  spfa1(int s){
      queue<int> q  ;
      memset(in , 0 , sizeof(in)) ;
      in[s] = 1 ;
      q.push(s) ;
      fill(dist1+1 , dist1+1+n , -inf) ;
      dist1[s] = c ;
      while(! q.empty()){ 
           int u = q.front() ; q.pop() ;
           in[u] = 0  ;
           for(int i = g1.lis[u] ; i != -1 ; i = g1.e[i].next){
                int v = g1.e[i].v  , w = g1.e[i].w ;
                if(dist1[u] >= w){ //能走完这条路
                     int t = dist1[u] - w ;
                     if(fuel[v]) t = c ;
                     if(dist1[v] < t){
                           dist1[v] = t ;
                           if(! in[v]){
                                  in[v] = 1 ; q.push(v) ;
                           }
                     }
                }
           }
      }
}

void  spfa2(int s){
      queue<int> q  ;
      memset(in , 0 , sizeof(in)) ;
      in[s] = 1 ;
      q.push(s) ;
      fill(dist2+1 , dist2+1+n , inf) ;
      dist2[s] = 0 ;
      while(! q.empty()){
           int u = q.front() ; q.pop() ;
           in[u] = 0  ;
           for(int i = g2.lis[u] ; i != -1 ; i = g2.e[i].next){
                int v = g2.e[i].v  , w = g2.e[i].w ;
                if(dist2[u] + w <= c){ //能走完这条路
                     int t = dist2[u] + w ;
                     if(fuel[v]) t = 0 ;
                     if(dist2[v] > t){
                         dist2[v] = t ;
                         if(! in[v]){
                              in[v] = 1 ; q.push(v) ;
                         }
                     }
                }
           }
      }
}

int  main(){
     int i , u , v , w  , p  , q  , s ;
     while(cin>>n>>m>>c){
          g1.Clear() , g2.Clear()  ;
          for(i = 1 ; i <= m ; i++){
               scanf("%d%d%d" , &u , &v , &w)  ;
               g1.add(u , v , w)  ;
               g2.add(v , u , w)  ;
          }
          memset(fuel , 0 , sizeof(fuel)) ;
          scanf("%d" ,&p) ;
          for(i = 1 ; i <= p ; i++){
               scanf("%d" ,&u) ;
               fuel[u] = 1 ;
          }
          scanf("%d" , &q) ;
          for(i = 1 ; i <= q ; i++)
              scanf("%d%d" ,&sell[i][0] , &sell[i][1]) ;
          spfa1(1) ;
          if(dist1[n] < 0){
               puts("-1") ; continue  ;
          }
          spfa2(n) ;
          s = 0  ;
          for(i = 1 ; i <= q ; i++){
               u = sell[i][0]  , w = sell[i][1] ;
               if(dist1[u] >= dist2[u])
                  s = max(s , (dist1[u] - dist2[u]) * w ) ;
          }
          printf("%d\n" , s) ;
     }
     return 0 ;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值