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;
    }
    
  • 相关阅读:
    Win8系统 Python安装
    一些安卓开源框架整理
    Android 媒体键监听以及模拟媒体键盘的实现 demo
    android View 自动 GONE 问题
    Android 定时器TimerTask 简单使用
    关于Android studio 相对 eclipse 优点
    Java序列化与反序列化
    android shape的使用 边框
    Android Studio 修改 包名 package name
    Android WebView Long Press长按保存图片到手机
  • 原文地址:https://www.cnblogs.com/streamazure/p/13396153.html
Copyright © 2011-2022 走看看