http://poj.org/problem?id=1062
Dijkstra算法详解:
http://blog.csdn.net/include_heqile/article/details/79577822
本题需要抽象成最短路问题,进而使用Dijkstra算法来解决,我们要求的就是从始点V0到终点V1的最短距离,其中V1就代表酋长
把每一个物品抽象成有向图中的节点,把本物品与替代品抽象成一条边,二优惠价格就是该边的权值,即adj[替代品][本物品],adj是一个邻接矩阵
注意方向是从替代品指向本物品的,因为最终的目标是酋长,因此这是一个回溯的过程
首先设置dist数组,并初始化dist数组中的每个节点,他们的值就是adj[0][当前节点]
本题最关键的一点就是,当前节点能访问到的节点是有限制的,和等级低的人交易过之后,等级高的人就不会再和冒险家交易,还有一个限制条件就是与冒险家进行交易的两个人的等级差距不能超过给定的M值
这样以来,我们在执行Dijkstra算法之前就需要对一些节点进行限制,就是使用标记数组vis标记他们,使得这些节点不参与最短路的寻找过程
代码参考自:
如果你的运行环境无法运行改代码,尝试把scanf_s改为scanf
代码如下:
#include<stdio.h>
#include<string.h>
#define maxn 10001
#define min(x, y) (x)<(y)?(x):(y)
int dist[10001];
int lv[101]; //记录物品的等级
int adj[101][101]; //记录两个物品组成的边的权值
//其实就是抽象成了邻接矩阵
//当第一个索引值为0的时候,adj[0][i]表示的是物品i的原价
int vis[10001];
int m, n;
void init() {
memset(dist, maxn, sizeof(dist));
memset(adj, maxn, sizeof(adj));
memset(vis, 0, sizeof(vis));
memset(lv, 0, sizeof(lv));
scanf_s("%d%d", &m, &n);
for(int i = 1; i <= n; i++) {
int t_1, t_2, t_3, t_4, t_5;
scanf_s("%d%d%d", &t_1, &t_2, &t_3);
adj[0][i] = t_1;
lv[i] = t_2;
for(int j = 0; j < t_3; j++) {
scanf_s("%d%d", &t_4, &t_5);
adj[t_4][i] = t_5;
}
}
}
void dijkstra() {
for(int i =1; i <= n; i++)
dist[i] = adj[0][i];
for(int i = 1; i <= n; i++) {
int k = 0;
int minx = maxn;
for(int j = 1; j <= n; j++) {
if(!vis[j] && dist[j] < minx) {
minx = dist[j];
k = j;
}
}
if(!k) break;
vis[k] = 1;
for(int j = 1; j <= n; j++) {
if(!vis[j] && dist[k] + adj[k][j] < dist[j])
dist[j] = dist[k] + adj[k][j];
}
}
}
int main() {
init();
int minx = maxn;
for(int i = 1; i<= n; i++) {
int mmaxn = lv[i];
for(int j = 1; j <= n; j++) {
//这样的物品是访问不到的,高等级的人不会和冒险家交易
//因为冒险家和比自己等级低的人进行了交易
//等级差超过了m也是无法访问到的节点
//可见这个图其实是被lv[i]的等级所约束的
if(lv[j] > mmaxn || mmaxn - lv[j] > m)
vis[j] = 1;
else
vis[j] = 0;
}
dijkstra();
minx = min(minx, dist[1]);
}
printf("%d\n", minx);
return 0;
}