这道题由于有N个物品,我们就可以把它们看作是N个点,从其他点到他的优惠关系视做边,又因为最后总是要找到物品1,所以可以看作是从起点0,到将物品1作为终点的最小路径。然后由于题目是说,这条路劲上不能有两个的等级差超过M,所以我们可以枚举最小等级,将每个点的级数视作最小等级,每次都进行一次dijkstra算法,这样的话就不会掉解。
又由于我们是枚举的最小等级,所以源点0到其他每个点的边的权值就要赋值为那个点的价格,则等级比最小等级小的,或者等级减去最小等级比M大的其他点标记为不合法(也就是不可以走),然后在从合法的路径中找出最小花费。代码:
#include <stdio.h>
#include <string.h>
#define INF 0x3f3f3f3f
int n,m;
int map[105][105];
int dis[105];
int money[105];
int level[105];
int minLevel;
int vis[105];
void Init() //初始化
{
int i,j;
for(i=0;i<=n;i++)
{
for(j=0;j<=n;j++)
{
if(i==j)map[i][j]=0;
else map[i][j]=INF;
}
}
}
void Dij()
{
int i,j;
for(i=0;i<n;i++)
{
int min=INF;
int u=-1;
for(j=1;j<=n;j++)
{
if(level[j]<minLevel)continue;
if(level[j]-minLevel>m)continue; //等级不符合条件
if(dis[j]<min&&!vis[j])
{
min=dis[j];
u=j;
}
}
if(u==-1)break;
vis[u]=1;
for(j=1;j<=n;j++)
{
if(level[j]<minLevel)continue;
if(level[j]-minLevel>m)continue; //等级不符合条件
if(!vis[j]&&dis[j]>dis[u]+map[u][j])
dis[j]=dis[u]+map[u][j];
}
}
}
int main()
{
int i,j;
while(scanf("%d %d",&m,&n)!=EOF)
{
Init();
for(i=1;i<=n;i++)
{
int a;
scanf("%d %d %d",&money[i],&level[i],&a);
for(j=0;j<a;j++)
{
int b,c;
scanf("%d%d",&b,&c);
map[b][i]=c;
}
map[0][i]=money[i];
}
int ans=INF;
for(i=1;i<=n;i++) //枚举最小等级
{
minLevel=level[i];
for(j=1;j<=n;j++)dis[j]=map[0][j];
dis[0]=0;
memset(vis,0,sizeof(vis));
vis[0]=1;
Dij();
if(ans>dis[1])ans=dis[1];
}
printf("%d\n",ans);
}
return 0;
}