zoukankan      html  css  js  c++  java
  • 【原】 POJ 1062 昂贵的聘礼 Dijkstra 解题报告

    http://poj.org/problem?id=1062


    方法:
    枚举+dijkstra
    难点在于将问题具体化为求最短路的问题。将每个物品视为编号2~n的节点,编号为1的节点为酋长
    的要求,编号为0的节点为旅行家。图中的边(u,v)表示由u到v所需要花费的金钱。所以(0,1)为酋
    长的初始要求,(0,2~n)为每个物品本身的价格。若物品v可以用u加上花费c来代替,那么(u,v)=c

    利用dijkstra求节点0到1的最短路径。因为有等级限制m,所以枚举等级限制内的包含酋长等级的
    所有可能的等级范围,对在此等级范围内的图求0到1的最短路径。最终所有枚举的最短路径的最
    小值即为所求的结果

    注意:
    1、每次枚举之后要重新设置Table T
    2、将旅行者的等级设置成和酋长相同,这样再枚举所有等级范围时,旅行者都在范围内。
    3、酋长的等级并不是最高的

    Description

    年轻的探险家来到了一个印第安部落里。在那里他和酋长的女儿相爱了,于是便向酋长去求亲。酋长要他用10000个金币作为聘礼才答应把女儿嫁给他。探险家拿不出这么多金币,便请求酋长降低要求。酋长说:"嗯,如果你能够替我弄到大祭司的皮袄,我可以只要8000金币。如果你能够弄来他的水晶球,那么只要5000金币就行了。"探险家就跑到大祭司那里,向他要求皮袄或水晶球,大祭司要他用金币来换,或者替他弄来其他的东西,他可以降低价格。探险家于是又跑到其他地方,其他人也提出了类似的要求,或者直接用金币换,或者找到其他东西就可以降低价格。不过探险家没必要用多样东西去换一样东西,因为不会得到更低的价格。探险家现在很需要你的帮忙,让他用最少的金币娶到自己的心上人。另外他要告诉你的是,在这个部落里,等级观念十分森严。地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。他是一个外来人,所以可以不受这些限制。但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。因此你需要在考虑所有的情况以后给他提供一个最好的方案。
    为了方便起见,我们把所有的物品从1开始进行编号,酋长的允诺也看作一个物品,并且编号总是1。每个物品都有对应的价格P,主人的地位等级L,以及一系列的替代品Ti和该替代品所对应的"优惠"Vi。如果两人地位等级差距超过了M,就不能"间接交易"。你必须根据这些数据来计算出探险家最少需要多少金币才能娶到酋长的女儿。

    Input

    输入第一行是两个整数M,N(1 <= N <= 100),依次表示地位等级差距限制和物品的总数。接下来按照编号从小到大依次给出了N个物品的描述。每个物品的描述开头是三个非负整数P、L、X(X < N),依次表示该物品的价格、主人的地位等级和替代品总数。接下来X行每行包括两个整数T和V,分别表示替代品的编号和"优惠价格"。

    Output

    输出最少需要的金币数。

    Sample Input

    1 4

    10000 3 2

    2 8000

    3 5000

    1000 2 1

    4 200

    3000 2 1

    4 200

    50 2 0

    Sample Output

    5250

       1: #include <stdio.h>
       2: #include <iostream>
       3: #include <vector>
       4:  
       5: using namespace std ;
       6:  
       7: const int INF = 0x7fffffff ;
       8:  
       9: //邻接点
      10: struct Vertex
      11: {
      12:     int vertex ;
      13:     int weight ;
      14: };
      15:  
      16: struct tSlot
      17: {
      18:     tSlot():known(false),dist(INF){}
      19:     bool known ;
      20:     int dist ;
      21: };
      22:  
      23: typedef vector< vector< struct Vertex > > Graph ;
      24: typedef vector< struct tSlot > Table ;
      25: typedef vector< int > Rank ;
      26:  
      27: Graph G ;
      28: Table T ;
      29: Rank R ;  //存储每个节点的等级
      30:  
      31: void ReadGraphAndTable( int n )
      32: {
      33:     int id,price,rank,subItemNum ;
      34:     int i ;
      35:     Vertex tmpVertex ;
      36:  
      37:     //图中编号:0表示探险家,1表示酋长,2~n表示各物品,n+1作为哨兵以判断dijkstra算法结束
      38:     G.resize(n+2) ;
      39:     T.resize(n+2) ;
      40:     R.resize(n+2) ;
      41:  
      42:     for( i=1 ; i<=n ; ++i )
      43:     {
      44:         scanf( "%d%d%d", &price,&rank,&subItemNum );
      45:         tmpVertex.vertex = i ;
      46:         tmpVertex.weight = price ;
      47:         G[0].push_back(tmpVertex) ;
      48:         R[i] = rank ;
      49:  
      50:         while( subItemNum-- )
      51:         {
      52:             scanf( "%d%d", &id,&price ) ;
      53:             tmpVertex.vertex = i ;
      54:             tmpVertex.weight = price ;
      55:             G[id].push_back(tmpVertex) ;
      56:         }
      57:     }
      58:  
      59:     T[0].dist = 0 ;
      60:     R[0] = R[1] ;  //将旅行者的等级设置成和酋长相同
      61: }
      62:  
      63: //求得节点rank范围在[minRank,maxRank]的图中0到1的最短距离
      64: int Dijkstra( int minRank , int maxRank , int n )
      65: {
      66:     int i ;
      67:     int adjv,w ;
      68:     int minUnknown ;
      69:     int minDist ;
      70:     vector< struct Vertex >::iterator vIter ;
      71:  
      72:     while( true )
      73:     {
      74:         //找到未知的距离最短的节点,且rank要在范围内
      75:         minUnknown = n+1 ;  //****
      76:         for( i=0 ; i<=n ; ++i )
      77:         {
      78:             if( !T[i].known && R[i]>=minRank && R[i]<=maxRank )
      79:                 minUnknown = T[minUnknown].dist<T[i].dist ? minUnknown : i ;
      80:         }
      81:  
      82:         //此时所有节点都求得了最短路径
      83:         if( minUnknown == n+1 )
      84:             break ;
      85:  
      86:         //此时已经求得0到1的最短路径
      87:         if( minUnknown == 1 )
      88:             break ;
      89:  
      90:         //贪心选择
      91:         //将该节点标记为已知,即已找到最短距离
      92:         T[minUnknown].known = true ;
      93:  
      94:         //更新未知邻接点的最短距离,且rank要在范围内
      95:         for( vIter=G[minUnknown].begin() ;  vIter!=G[minUnknown].end() ; ++vIter )
      96:         {
      97:             adjv = vIter->vertex ;
      98:             w = vIter->weight ;
      99:             
     100:             if( !T[adjv].known && R[adjv]>=minRank && R[adjv]<=maxRank )
     101:             {
     102:                 if( T[minUnknown].dist+w <= T[adjv].dist )
     103:                      T[adjv].dist = T[minUnknown].dist+w ;
     104:             }
     105:         }
     106:     }
     107:  
     108:     //返回0到1的最短距离
     109:     return T[1].dist ;
     110: }
     111:  
     112: void run1062()
     113: {
     114:     int m,n ;
     115:     int minRank,maxRank ;
     116:     int minDist,tmpDist ;
     117:  
     118:     scanf( "%d%d", &m,&n ) ;
     119:  
     120:     ReadGraphAndTable(n) ;
     121:  
     122:     //枚举等级限制内的包含酋长等级的所有可能的等级范围
     123:     minDist = INF ;
     124:     for( minRank=R[1]-m ; minRank<=R[1] ; ++minRank )
     125:     {
     126:         maxRank = minRank+m ;
     127:  
     128:         tmpDist = Dijkstra( minRank , maxRank , n ) ;
     129:         minDist = minDist<tmpDist ? minDist : tmpDist ;
     130:  
     131:         //枚举之后要重新设置Table T
     132:         T.clear() ;
     133:         T.resize(n+2) ;
     134:         T[0].dist = 0 ;
     135:     }
     136:  
     137:     printf( "%d\n" , minDist ) ;
     138: }

    如果您满意我的博客,请点击“订阅Allen Sun的技术博客”即可订阅,谢谢:)

    原创文章属于Allen Sun
    欢迎转载,但请注明文章作者Allen Sun和链接
  • 相关阅读:
    我的游戏学习日志11——小结(1)
    我的游戏学习日志10——数字游戏策划(5)游戏策划的概念与分工
    我的游戏学习日志9——数字游戏策划(4)数字游戏的特征
    我的游戏学习日志8——数字游戏策划(3)数字游戏的概念
    我的游戏学习日志7——数字游戏策划(2)游戏的概念以及其学术上的分类
    我的游戏学习日志6——数字游戏策划(1)游戏理论发展
    我的游戏学习日志5——拳皇97_(不得不吹的经典)
    我的游戏学习日志4——冒险岛
    我的游戏学习日志3——三国志GBA
    C++小坑汇总
  • 原文地址:https://www.cnblogs.com/allensun/p/1869406.html
Copyright © 2011-2022 走看看