//这道题的大概意思是,从酋长的承诺开始,通过以替代物换优惠,一路置换,到最后主角付出的价值最小。
//一看是很简单的最短路径问题,求原点到其他顶点的最小花费,取花费最小的值输出即可,但这里有个等
//级区间限制,需要在外层再套一层循环枚举区间。
//用图的邻接表来存数据,然后枚举区间进入循环,再排除不可用顶点,用dijkstra算法来解决定顶点到各
//点的最小权值,最后取点和当前最小权值(一开始为最大值)比较,走完循环最小点即为结果。
//#include <Windows.h>
#include <iostream>
#include <cstdio>
#include <malloc.h>
#include <cmath>
using namespace std;
#define MAXV 101//最大顶点数
#define MAXS 65535//最大权值
typedef struct ANode
{
int adjvex;//该边的终点编号,该边指向能优惠的置换物
struct ANode *nextarc;//指向下一条边的指针,指向下一个能优惠的置换物
int discount;//给该置换物后头节点的优惠价格
}ArcNode;//边节点类型
typedef struct Vnode
{
int orderNum;//物品顶点序号
int value;//物品顶点价值
int rank;//该物品持有者等级
ArcNode *firstarc;//指向第一条边
}VNode;//邻接表头节点类型
typedef VNode AdjList[MAXV];//AdjList是邻接表类型
typedef struct
{
AdjList adjlist;//邻接表
int n,e;//图中顶点数n和边数e
}ALGraph;//完整的图邻接表类型
int main()
{
int m,n,p,l,x,t,v;//这个是题目要求的数据
int qd=1,u,min,sumMin;//qd是起点(即酋长的允诺),u,min为算法过程中保存当前情况最小权值点序号以及最小权值,sumMin为结果
int path[MAXV];//这个其实多余的,保存最小路径用
int dist[MAXV];//到达该点的最小花费
int s[MAXV];//s[i]为1则为已找到i顶点的最短路径和最小权值
ALGraph *G;//用图的邻接表结构存储该题数据
//while((scanf("%d%d",&m,&n))&&(m!=0&&n!=0))
scanf("%d%d",&m,&n);
{
G=(ALGraph *)malloc(sizeof(ALGraph));
G->n=n;G->e=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&p,&l,&x);
//物品存入头顶点
G->adjlist[i].orderNum=i;
G->adjlist[i].value=p;
G->adjlist[i].rank=l;
G->adjlist[i].firstarc=NULL;//这一步不要忘了,不然会读取越界
G->e+=x;
for(int j=0;j<x;j++)
{
scanf("%d%d",&t,&v);
//置换途径存入边节点
ArcNode *z;
z=(ArcNode *)malloc(sizeof(ArcNode));
z->adjvex=t;
z->discount=v;
z->nextarc=G->adjlist[i].firstarc;
G->adjlist[i].firstarc=z;
}
}
sumMin=MAXS;
for(int qmin=G->adjlist[1].rank-m;qmin<=G->adjlist[1].rank;qmin++)//枚举区间
{
int qmax=qmin+m;//qmin为区间最小值,qmax为区间最大值
//初始化工作
for(int i=0;i<MAXV;i++)
{
path[i]=-1;
dist[i]=MAXS;
s[i]=0;
}
//起点顶点处理,并把相邻边写入
dist[qd]=0;
s[qd]=1;
ArcNode *z;
z=G->adjlist[qd].firstarc;
while(z!=NULL)//如果存在边,则存入
{
if((G->adjlist[z->adjvex].rank>=qmin)&&(G->adjlist[z->adjvex].rank<=qmax))//该边符合等级限制,则存入
{
//printf("%d %d %d\n",qmin,G->adjlist[z->adjvex].rank,qmax);
dist[z->adjvex]=z->discount;//花费存入,即到达该顶点的最小花费
path[z->adjvex]=qd;//路径存入
}
z=z->nextarc;
}
//循环查找部分,共循环n-1次
for(int i=1;i<G->n;i++)
{
//选一个还没找到最短路径但离起点最近的顶点,置为已找到最短路径
min=MAXS;
u=MAXV;
for(int j=2;j<=G->n;j++)
{
if(s[j]==0&&dist[j]<min)
{
min=dist[j];
u=j;
}
}
if(u==MAXV) break;//如果找不到了,证明可能有不连通或者不符等级区间的头节点,直接结束
s[u]=1;//该顶点已找到最短路径
//将该顶点相关的路径遍历一边,更新相邻顶点较短路径
ArcNode *z2;
z2=G->adjlist[u].firstarc;
while(z2!=NULL)//如果存在边且该边符合等级限制,则存入
{
if((G->adjlist[z2->adjvex].rank>=qmin)&&(G->adjlist[z2->adjvex].rank<=qmax))
{
if(z2->discount+dist[u]<dist[z2->adjvex])//如果当前方案比以往置换方案更少钱,则替换
dist[z2->adjvex]=z2->discount+dist[u];//花费存入,折扣+替代物价值
path[z2->adjvex]=u;//路径存入
}
z2=z2->nextarc;
}
}
//在最小权值表中选出最小权值即为该题结果
for(int i=1;i<=G->n;i++)
{
if(dist[i]+G->adjlist[i].value<sumMin) sumMin=dist[i]+G->adjlist[i].value;
}
}
cout<<sumMin<<endl;
//free(G);
}
//Sleep(60000);
return 0;
}