zoj 3794 spfa

来源:互联网 发布:日本动漫配音软件 编辑:程序博客网 时间:2024/05/16 17:44


给定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
原创粉丝点击