poj 1062_最短路径

题目描述:

  和主人交换物品,物品可以由别人的物品+money来替代。人和人之间交换有等级限制。求怎么能用最少的钱得到和主人交换的那个物品。

  转化为问题:1)节点有自己的权值,边也有权值,若across一个节点,则总权值不用加入该节点的权值,即每条路径的权值 = across的边的权值 + 最后一个点的权值。(2)节点存在等级值,一条路径上的节点等级差不超过m。求从主人那个点出发,最少权值的路试哪一条。

 

解题思路:

定点出发,求最短路径,基本思想是贪心——迪杰斯特拉(每次选择最短的边)。这里将图存成三元组的序列。存路径长度数组D[j](存出发点到j的最短路径值),记录出发点到任意符合条件点的路径长,最后加上末尾节点的权值W[j]。贪心过程记录下路径上的等级值Level[j][2],其中[j][0]表示贪心到j点的时候路径上的最低等级,[j][1]指路径上最高等级。利用等级值来判断加入一个新点的时候,下一个节点上的贪心值是否改变(这个更新值为走上一节点的路径才可能达到)。

时间复杂度为 O(v2)

 

代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define N 101
#define Infinity 1000000000

typedef struct {
        int l;
        int cash;
        int t;
        int T[N][2];
}Deal;

int m,n;
Deal deal[N];
int D[N], final[N];
int record[N][2];
main()
{
   int i,j;
   int min;
   int w,flag;
  
   scanf("%d %d",&m, &n);
   for(i=1;i<=n;i++)
   {
       scanf("%d",&deal[i].cash);
       scanf("%d",&deal[i].l);
       scanf("%d",&deal[i].t);
       for(j=1;j<=deal[i].t;j++)
          scanf("%d %d",&deal[i].T[j][0],&deal[i].T[j][1]);
   }
   for(i=1; i<=n; i++)
      for(j=1;j<=deal[i].t;j++)
         if(fabs(deal[i].l - deal[deal[i].T[j][0]].l) > m)
            deal[i].T[j][1] = Infinity;  
  
   //initialize
   for(i=1; i<=n; i++)
   {
      D[i] = Infinity;
      final[i] = 0;
   }
   D[1] = 0;
   record[1][0] = deal[1].l;
   record[1][1] = deal[1].l;
   final[1] = 1;
   for(i=1; i<=deal[1].t;i++)
   {
      if(fabs(deal[deal[1].T[i][0]].l - deal[1].l) <= m)
      {
         if(deal[deal[1].T[i][0]].l > deal[1].l)
         {
            record[deal[1].T[i][0]][1] = deal[deal[1].T[i][0]].l;
            record[deal[1].T[i][0]][0] = deal[1].l;
         }
         else if(deal[deal[1].T[i][0]].l < deal[1].l)
         {
             record[deal[1].T[i][0]][0] = deal[deal[1].T[i][0]].l;
             record[deal[1].T[i][0]][1] = deal[1].l;
         }
         else
         {
             record[deal[1].T[i][0]][1] = deal[1].l;
             record[deal[1].T[i][0]][0] = deal[1].l;
         }
      }
      D[deal[1].T[i][0]] = deal[1].T[i][1];
  }

  
   w = 1;
   for(i=2; i<=n; i++)
   {
      min = Infinity;
      flag = 0;
      for(j=2; j<=n; j++)
         if(!final[j])
         {
            if(D[j] < min)
            {
               w = j;
               min = D[j];
               flag = 1;
              
            }
         }
      if(flag == 0)
         continue;
      final[w] = 1;
      for(j=1; j<= deal[w].t; j++)
      {
         if(!final[deal[w].T[j][0]])
         {
            if(min+deal[w].T[j][1] < D[deal[w].T[j][0]])
            {
               if((fabs(deal[deal[w].T[j][0]].l-record[w][0]) <= m) &&(fabs(deal[deal[w].T[j][0]].l - record[w][1]) <= m))
               {
                  if(deal[deal[w].T[j][0]].l > record[w][1])
                  {
                      record[deal[w].T[j][0]][1] = deal[deal[w].T[j][0]].l;
                      record[deal[w].T[j][0]][0] = record[w][0];
                  }
                  else if(deal[deal[w].T[j][0]].l < record[w][0])
                  {
                     record[deal[w].T[j][0]][0] = deal[deal[w].T[j][0]].l;
                     record[deal[w].T[j][0]][1] = record[w][1];
                  }
                  else
                  {
                     record[deal[w].T[j][0]][0] = record[w][0];
                     record[deal[w].T[j][0]][1] = record[w][1];
                  }
                  D[deal[w].T[j][0]] = min+deal[w].T[j][1];
               }
            }
         }
      }
   }
   min = Infinity;
   for(i=1; i<=n; i++)
   {
      if(fabs(deal[i].l - deal[1].l) > m)
         D[i] = Infinity;
      else
         D[i] += deal[i].cash;
        
      if(D[i] < min)
         min = D[i];
  
   printf("%d\n",min);
   //system("pause");
   return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值