/**
* dijkstra :
* 这题题目有点坑: 说的是等级高的不愿和等级低的间接接触,没有说等级低的不愿和等级高的间接接触。
* 比如: 有三个人 A level: 3 B level: 4 C level: 5 如果B先和A接触,C不愿和A接触,而B先和C接触,A也不愿和B接触。
* 既然是这样的话,就只能设置多个限制了。而且要对各定点进行枚举。
* 首先说模型吧。 每个节点就每个物品,权值为金币数。 这题关键就是个等级限制
* 在枚举每个节点的时候,可以先设置好限制,具体就是:
* 1、删除等级差大于m的点;
* 2、把当前节点看做是最大(或者最小)的等级,也就是把所有等级大于当前节点的节点删去。
* 这一步是很重要的,如果不这样做的话,就会导致之前说的,A,B,C三个人,B先和C再和A。
* 如何实现dijkstra算法:
* 在无向无权图(或者看成权为1)中,用dijkstra的时候是对某个指定的单源点进行求到个节点的最短路径。
* 这个时候dis就是和源点的距离,每次找最小的dis继续遍历找可行的边。
* 而这题是个有向有权图,其实也一样! 首先dis[]就表示开始的权值(原价格),因为不可能换来换去要比这些大。
* 然后找dis[]中最小的一步一步和无向无权图的dijkstra一样遍历n次,每次再更新下最小值。
* 还有要注意的是,这不是个连通的图,也就是并不是在枚举每个源点的时候都能够到达酋长的节点。
* 所以当在搜最小dis的时候,如果没有搜到,也就是没有其他边通向新的节点了,就要break出来。
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <algorithm>
#define DEBUG 0
#define INF 0x7fffffff
#define MAXS 101
typedef long long LL;
using namespace std;
int m, n, dp[MAXS][MAXS], price[MAXS], vis[MAXS], level[MAXS];
struct Change {
int NO, p;
Change(int x, int y) {NO = x; p = y;}
Change() {}
};
vector<Change> vec[MAXS];
inline void init_vec() {
for(int i = 1; i <= n; i ++) {
vec[i].clear();
}
}
bool judge(int x, int y, int &changePrice) {
if(abs(level[x] - level[y]) > m) return false;
for(vector<Change>::size_type i = 0; i != vec[y].size(); i ++) {
if(vec[y][i].NO == x) {
changePrice = vec[y][i].p;
return true;
}
}
return false;
}
int dis[MAXS]; /** 用来存当前起始源i到dis[j]的路径,用于dijkstra时搜索当前最短路径的.*/
void dijkstra() {
int ans = INF;
if(DEBUG) {
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= n; j ++)
printf("%d ", dp[i][j]);
printf("\n\n");
}
}
for(int i = 1; i <= n; i ++) {
int curMin, x;
memset(vis, 0, sizeof(vis));
/** 标记vis,将等级差大于m的点删去(可以直接设vis为1)*/
for(int j = 1; j <= n; j ++) {
if(abs(level[j] - level[i]) > m || level[j] > level[i]) vis[j] = 1; /** 审题 */
dis[j] = price[j];
}
for(int j = 1; j <= n; j ++) {
curMin = INF;
for(int k = 1; k <= n; k ++) {
if(!vis[k] && dis[k] < curMin) {
curMin = dis[k];
x = k;
}
}
if(curMin == INF) break;
vis[x] = 1;
int changePrice;
if(DEBUG) {
if(i == 5 && x == 4)
x = 4;
}
for(int k = 1; k <= n; k ++) {
if(!vis[k] && judge(x, k, changePrice) &&
dis[k] > dis[x] + changePrice) {
dis[k] = dis[x] + changePrice;
}
}
}
if(ans > dis[1]) ans = dis[1];
}
printf("%d\n", ans);
}
int main()
{
while(scanf("%d%d", &m, &n) != EOF) {
init_vec();
for(int i = 1; i <= n; i ++) {
int k;
scanf("%d%d%d", &price[i], &level[i], &k);
Change curC;
for(int j = 1; j <= k ; j ++) {
scanf("%d%d", &curC.NO, &curC.p);
vec[i].push_back(curC);
}
}
dijkstra();
if(DEBUG) {
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= n; j ++)
printf("%d ", dp[i][j]);
printf("\n\n");
}
}
}
return 0;
}
POJ 1062 枚举单源最短路径(dijkstra算法)
最新推荐文章于 2023-01-16 21:44:19 发布