POJ-1062 昂贵的聘礼 解题报告

Dijstra算法

题目链接: POJ-1062 昂贵的聘礼

解题思路

通过题意,我们可以很明显的看出来,物品的交换流程可以构成一个有向图,而且这个图是有边权的。

构建这个图的过程如下:
因为每个物品都有相应的替代物品,所以我们可以在替代物品和该物品之间建立一条边,从替代物品指向该物品,并且边上的权值为优惠价格。这样建完所有的边之后,我们可以创造一个起点,这个起点对所有的物品都有一个出边,并且边上的权值为该物品的原价。最终我们的结果肯定是一个从起点到编号为1的物品的最短路。

通过上面的分析,现在我们的问题是如何将每个物品主人的等级考虑进去,根据题意我们了解到,我们最终的结果是在那条最短路上,最高的等级与最低的等级之间的差不能超过M,这里是特别容易弄错的地方,我之前以为是如果A与B之间的等级差小于M,B与C之间的等级差小于M就能一直从A交换到C……

解题关键:最终的我们得到的最短路,里面肯定是有一个点X的等级是最低的,那么我们可以在原图上找到所有的比这个X点等级高的,而且那些点与X点之间的等级差必须小于等于M,最终的路径肯定是这些点里面产生的。所以我们枚举每一个可能的点,将这个被枚举的点当作X点,然后找到所有满足上述条件的其他点,在这些点之间跑单源最短路。每次枚举X点我都能得到一个最短路径值,最终我们取最小的路径值便是结果。

解题代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 110;
const int INF = 0X3fffffff;

int M,N;
int dis[MAXN][MAXN];
int cost[MAXN];
bool vis[MAXN];
struct Node {
    int price;
    int level;
    int itemCount;
    int itemNum[MAXN];
    int itemPrice[MAXN];
}node[MAXN];

void initDis() {
    for(int i = 0; i <= N; i++) {
        dis[i][i] = 0;
        for(int j = i+1; j <= N; j++) {
            dis[i][j] = dis[j][i] = INF;
        }
    }
}
void initCost() {
    cost[0] = 0;
    for(int i = 1; i <= N; i++) {
        cost[i] = INF;
    }
}

void buildGraph() {
    for(int i = 1; i <= N; i++) {
        dis[0][i] = node[i].price;
        for(int j = 0; j < node[i].itemCount; j++) {
            int id = node[i].itemNum[j];
            int val = node[i].itemPrice[j];
            dis[id][i] = val;
        }
    }
}

int dijkstra(int x) {
    memset(vis, false, sizeof(vis));
    initCost();
    for(int i = 1; i <= N; i++) {
        if(node[x].level <= node[i].level && node[i].level-node[x].level <= M) {
            cost[i] = dis[0][i];
        }
    }
    vis[0] = true;
    for(int i = 1; i <= N; i++) {
        int _min = INF;
        int p = -1;
        for(int j = 0; j <= N; j++) {
            if(!vis[j] && _min > cost[j]) {
                p = j;
                _min = cost[j];
            }
        }
        if(-1 == p || INF == _min)continue;
        vis[p] = true;
        for(int j = 0; j <= N; j++) {
            if(!vis[j] && cost[j] > cost[p]+dis[p][j] &&
               node[x].level <= node[j].level && node[j].level-node[x].level <= M) {
                cost[j] = cost[p]+dis[p][j];
            }
        }
    }
    return cost[1];
}

int main() {
    while(~scanf("%d%d", &M, &N)) {

        initDis();

        for(int i = 1; i <= N; i++) {
            scanf("%d%d%d", &node[i].price, &node[i].level, &node[i].itemCount);
            for(int j = 0; j < node[i].itemCount; j++) {
                scanf("%d%d", &node[i].itemNum[j], &node[i].itemPrice[j]);
            }
        }

        buildGraph();

        int ans = INF;
        for(int i = 1; i <= N; i++) {
            ans = min(dijkstra(i), ans);
        }

        printf("%d\n", ans);
    }
    return 0;
}

转载于:https://www.cnblogs.com/yinzm/p/5937219.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值