zoukankan      html  css  js  c++  java
  • 【最短路+区间枚举】昂贵的聘礼 POJ

    昂贵的聘礼 POJ - 1062

    题意:

    原题干说得不清不楚的……坑死我了。

    • 探险家要得到物品(i),方式有两种:一、花费金币(P[i])直接买;二、先得到指定物品(X),然后可以优惠价格(V)买得。
    • 每个物品都有地位等级。
    • 给定地位等级差距限制(M),表示可行的交易序列中最高地位等级与最低地位等级之差应≤(M),超出此范围时不可交易。如(M=2)时,若要买到地位等级为(4)的物品,则交易序列中的物品等级只能为以下范围:({2,3,4}或{3,4,5}或{4,5,6})
    • 探险家的最终目的是得到物品(1)。问他要花费的最少金币数。
    • 多组数据输入

    思路:

    把每个物品视为图的节点。通过物品(X)以优惠价格(V)买到物品(i),可视为从节点(X)出发,连接到节点(i),边权为(V)的单向边。原题目即最短路问题。

    在选定起点求最短路时,注意以下几点:

    1.起点本身是要花钱的,而且这个价格不应该被最短路计算改变。

    2.选定起点后求得的最短路所经过的所有节点,其地位等级都应满足差距限制M。

    3.物品1是可以直接花钱买的,其他起点求出的最短路要和这个价格再比较一下。

    要实现第2点,最简单的就是从物品(1)的地位等级出发,枚举可行的等级范围。再从这个等级范围里枚举所有可行起点计算最短路,并且注意最短路里经过的所有节点都要满足这个等级范围。

    数据范围小,dijkstra、SPFA、floyd全都可以过,这里用最简洁的floyd。

    const int INF = 1e9;
    const int maxn = 100 + 10;
    
    struct node {
        int n;
        int level;
    };
    
    int d[maxn][maxn];
    int d_copy[maxn][maxn];
    int n, m;
    int up, down;
    int level[maxn];
    node Node[maxn];
    
    
    void floyd(int begin,int end) {
        for (int k = 1; k <= n; k++) {
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    if (i == j) continue;
                  //d[i][i]是直接买物品i的价格,这是固定的,不能改变
                    if (d_copy[i][k] + d_copy[k][j] < d_copy[i][j]) {
                        if (level[i]<begin || level[i]>end) continue;
                        if (level[j]<begin || level[j]>end) continue;
                        if (level[k]<begin || level[k]>end) continue;
                      //i,j,k节点都要在等级范围内,才能松弛
                        d_copy[i][j] = d_copy[i][k] + d_copy[k][j];
                    }
                }
            }
        }
    }
    
    int main()
    {
        // ios::sync_with_stdio(false);
        /// int t; cin >> t; while (t--) {
        int limit;
        //这是一个可滑动的窗口,不是以酋长等级为中位数的固定范围……
        while (cin >> limit >> n) {
            int ans = INF;
            int pos = 0;
            int L = 0;
            memset(level, 0, sizeof(level));
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    d[i][j] = INF;
                    d_copy[i][j] = INF;
                }
            }
            for (int i = 1; i <= n; i++) {
                int value, lev, sub;
                cin >> value >> lev >> sub;
                d[i][i]=d_copy[i][i] = value;
                if (i == 1) L = lev;
                node t;
                t.n = i; t.level = lev;
                Node[++pos] = t;
                level[i] = lev;
                for (int j = 1; j <= sub; j++) {
                    int from, dis;
                    cin >> from >> dis;
                    d[from][i] = d_copy[from][i]= dis;
                }
            }
    
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    if (d[i][j] < INF && abs(level[i] - level[j])>limit) {
                        d[i][j] = d_copy[i][j] = INF;
                    }
                }
            }
    
            up = L + limit;
            down = L - limit;
            if (down < 0) down = 0;
            //题目里说了地位等级都是非负整数
    
            //枚举等级区间
            for (int i = 0; i+down <= L; i++) {
                int begin = down + i;
                int end = begin + limit;
                //确定这个区间的等级上限和等级下限
                floyd(begin, end);
                //据此计算最短路,注意i,j,k均要在此等级范围内(尤其是k!不要忽略了)
                for (int j = 2; j <= n; j++) {
                    if (level[j]<begin || level[j]>end) continue;
                    ans = min(d_copy[j][j]+d_copy[j][1], ans);
                }
                //枚举起点的时候也要在等级范围内
                //不是枚举等级啊!!一开始写成了(int j=begin;j<=end;j++) 太弱智了
                //记得加上买起点的费用!!
    
                for (int j = 1; j <= n; j++) {
                    for (int k = 1; k <= n; k++) {
                        d_copy[j][k] = d[j][k];
                    }
                }
                //一定要把算出来的最短路清空掉!!还原回去!!才能计算下一个区间!!
            }
    
            ans = min(d[1][1], ans);
            //一定要把最后的答案再与直接买酋长礼物的价格再比较一下!!有时候直接买会更便宜
    
            cout << ans << endl;
            // }
        }
        return 0;
    }
    
  • 相关阅读:
    leetcode刷题笔记 273题 整数转换英文表示
    leetcode刷题笔记 278题 第一个错误的版本
    leetcode刷题笔记 268题 丢失的数字
    leetcode刷题笔记 264题 丑数 II
    leetcode刷题笔记 263题 丑数
    20210130日报
    20210129日报
    20210128日报
    20210127日报
    20210126日报
  • 原文地址:https://www.cnblogs.com/streamazure/p/13396153.html
Copyright © 2011-2022 走看看