POJ 1062 昂贵的聘礼

题目链接:http://poj.org/problem?id=1062

题目大意:这道题实际上就是图的最短路径问题

解题思路:建图, 结点为每件物品,把探险者也看成一个入度为零的节点,是n + 1结点之一,探险者到其他物品的直接连线的权值为物品的原始价格,其他 i -> j的边的权值为探险者获得i后换j

的优惠价格。应该注意的是,由于等级限制,如果你和level[1] - k级别的人交易过,那么你最多只能和level[1] - k + m进行交易,因此我们要对这m个等级范围进行枚举,每次枚举只考虑该等

级范围内的点,并求出n + 1点到1点的最小值(最短路,dijkstra),再记录多次枚举得到的最小值,最后的最小值即为所求答案。代码中还有详细的解释

注意点:

1.代码中涉及到了不少的数组,所以对于某些有特定含义的数组一定要进行初始化,以免在后面的数值比较时出错

2.在设置一个很大的数字时要小心,最好是不要设置为最大整型数Integer.MAX_VALUE,因为一旦它参与运算就会出现不可预料的错误,如果它只是进行数值比较的话,那么是可以的

3.这道题目解法很多,建图可以用邻接矩阵也可以用邻接表,求最短路径可以用Dijkstra 也可以用其他的方法(例如:spfa)

我AC的Java代码:

Memory: 5072K
Time: 1641MS

 

/**
 * @Author:胡家威  
 * @CreateTime:2011-7-16 上午09:09:57
 * @Description:AC
 */

package ACM.POJ;

import java.util.Scanner;

public class POJ1062 {

    public static int[][] map = new int[101][101];// matrix 表示图的邻接矩阵[有向图]
    public static int[] level = new int[101];// level
    public static int[] dist = new int[101];// distance 从0到该点的权值
    public static int[] mark = new int[101];// mark 标记是否可以和他进行交易
    public static int m;// level distance
    public static int n;// goods number
    public static int ans;// result
    //public static int INF = Integer.MAX_VALUE;//错误原因
    public static int INF = 10000000;

    public static void main(String[] args) {
        Scanner sin = new Scanner(System.in);
        m = sin.nextInt();// 等级限制和物品数目
        n = sin.nextInt();
        int i, j, k, t;
        for (i = 0; i <= n; i++) {
            for (j = 0; j <= n; j++) {
                map[i][j] = INF;// 初始化邻接矩阵
            }
        }
        for (i = 1; i <= n; i++) {
            map[0][i] = sin.nextInt();// 价格和等级
            level[i] = sin.nextInt();
            t = sin.nextInt();
            for (j = 1; j <= t; j++) {// 替代品
                k = sin.nextInt();
                map[k][i] = sin.nextInt();// 建立有权边
            }
        }
        dijkstra();
    }

    public static void dijkstra() {
        int i, j, k, start, min;
        ans=INF;
        for (k = 0; k <= m; k++) {// 枚举等级差
            for (i = 1; i <= n; i++) {
                if (level[i] - level[1] <= k && level[1] - level[i] <= m - k) {
                    mark[i] = 1;// 表示可以进行交易,即可以访问的点
                    dist[i] = map[0][i];
                } else {
                    mark[i] = 0;
                    dist[i] = INF;
                }
            }
            for (i = 1; i <= n; i++) {
                start = 1;//设置1为起点,如果没有可以的中间点,那么1也就是终点了
                min = INF;//这两个值每次循环时都要重置一下
                for (j = 1; j <= n; j++) {//得到距离最短的点
                    if (mark[j] == 1 && dist[j] < min) {//可以访问的点中距离最近的
                        start = j;
                        min = dist[j];
                    }
                }
                mark[start] = 0;//将刚刚得到的距离最短的点标记为不能访问了
                for (j = 1; j <= n; j++) {//由于新的点的加入,要修改距离值[从0开始到该点的最短距离值]
                    if (mark[j] == 1 && dist[j] > dist[start] + map[start][j]) {//修改其他的可以访问的点的距离值
                        dist[j] = dist[start] + map[start][j];
                    }
                }
            }
            if(ans>dist[1])
                ans=dist[1];
        }
        System.out.println(ans);
    }

}

转载于:https://www.cnblogs.com/yinger/archive/2011/07/18/2109040.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值