POJ 1062 枚举单源最短路径(dijkstra算法)

/**
*    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;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值