POJ 1062 昂贵的聘礼(迪杰斯特拉算法dijkstra+枚举等级区间)

//这道题的大概意思是,从酋长的承诺开始,通过以替代物换优惠,一路置换,到最后主角付出的价值最小。
//一看是很简单的最短路径问题,求原点到其他顶点的最小花费,取花费最小的值输出即可,但这里有个等
//级区间限制,需要在外层再套一层循环枚举区间。
//用图的邻接表来存数据,然后枚举区间进入循环,再排除不可用顶点,用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;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值