poj 1062 Dijkstra最短路

/*

  http://acm.pku.edu.cn/JudgeOnline/problem?id=1062

  解法:虚拟一个节点0,设第i物品的价格为p,则建一条有向边:path[0][i]=p;

        若通过i物品,可以价格p得到j物品,则建一条有向边:path[i][j]=p; 

        然后通过dijkstra求0到1的最短路

  特殊性:本题的特殊性为,等级。如果得到等级i的物品,则不能去交换比它等级高,或者比它低m等级的物品

          回忆一下dijkstra,是将所有的点集分为“已访问”和“未访问”两个集合(通过v标记数组来表示)

          每次,都找到两个集合的最短路径,然后将该路径上“未访问”的点,加入到“已访问”节点中。

          然后利用这个新加入的点,对“未访问”的节点进行松弛

          直到将目的节点t加入到“已访问”节点,或者无法找到最短路径,算法终止。  

          dijkstra是基于广搜的策略,与广搜相比,只不过松弛方法有所不同,其余都是一样的。所以第一次找到目的节点t时,已经是最优解了 

          在本题中,枚举所有的物品。比如现在枚举的是i物品,那么将所有不能与i共存(等级制度)在一条路径上的节点放入到“已访问”节点,这样在dij中

          便不会对这些点进行扩展。 

*/ 

 

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<vector>

#include<set>

#include<queue>

#include<map>

#include<cmath>

#include<cstring>

#include<algorithm>

#include<functional>

using namespace std;

const int INF=(1<<20)-1;

const double EPS=1e-8;

const int N=110;

int m,n;

int v[N];

int path[N][N];

int l[N];

 

int dijkstra(int s,int t)//s起点,t终点 

{

    int d[N];

    for(int i=1;i<=n;i++)d[i]=path[s][i];

    while(true)

    {

      int Min=INF,mark=-1;

      for(int i=1;i<=n;i++)

       if(!v[i]&&d[i]<Min){Min=d[i];mark=i;}

      if(mark==-1)break;

      v[mark]=true;           

      for(int i=1;i<=n;i++)

       if(!v[i]&&d[i]>d[mark]+path[mark][i])

         d[i]=d[mark]+path[mark][i];         

    }

    return d[t];

}

 

 

int main()

{

    //freopen("in.txt","r",stdin);

    //freopen("out.txt","w",stdout);

    int p,x,a,b;

    while(cin>>m>>n)

    {

      for(int i=0;i<=n;i++)

       for(int j=0;j<=n;j++)

        path[i][j]=INF;

      for(int i=1;i<=n;i++)//建图 

      {

        scanf("%d%d%d",&p,l+i,&x);

        path[0][i]=p;

        while(x--)

        {

          scanf("%d%d",&a,&b); 

          path[a][i]=b;        

        }

      }  

      int Min=INF;

      for(int i=1;i<=n;i++)//枚举

      {

         for(int j=1;j<=n;j++)//利用m进行分类

         {

           if(i==j)continue;

           if(l[i]<l[j]||l[i]-l[j]>m)v[j]=true;

           else v[j]=false;        

         }        

        Min=min(Min,dijkstra(0,1));      

      }               

      cout<<Min<<endl;              

    }

 

 

    //system("pause");

    return 0;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值