poj 1062 昂贵的聘礼

/*
 *  poj 1062 昂贵的聘礼

    数学模型:
        图模型,物品与替代物品之间的单向关系采用有向边表示,各定点表示物品。

        图的表示法: 邻接表法

    解题思路:
        单源点DFS遍历图,在给定的深度内找到最小的费用值。
        这里与DFS有点不同的是: 
            采用回溯策略遍历图中所有的边组合,找出最小的费用值。
            而DFS则在搜索的过程中发现某点已经访问过了,就不再搜索该点相关的出边了。
            同时,可能会重复搜素某个点,因此该点搜索的最小值可以记录下来,DP或者记忆化搜素

        最后再啰嗦句:
            DFS是图的遍历方法,而回溯和状态空间搜素是策略思想,DFS采用回溯实现,回溯更基础。
*/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <list>
#include <algorithm>

namespace {
    using namespace std;

    typedef struct SUB_OBJ
    {
        int v;
        int off_price;
    }SUB_OBJ_S; // 替代品

    typedef struct OBJ
    {
        int l;
        int price;
    }OBJ_S; // 物品
    
    const int N_MAX = 100;

    bool visited[N_MAX+1]; 
// 访问标记

    OBJ_S V[N_MAX+1]; // 点集
    
    list<SUB_OBJ_S> adj[N_MAX+1]; // 邻接表
    
    int n, m;

    // 给定的深度范围内找到最小的费用值,每次深度加深,该范围会随之变化
    int dfs(int v, int level_bottom, int level_top)
    {
        int money = V[v].price;

        visited[v] = true; // 进入置访问标志
        for (list<SUB_OBJ_S>::iterator iter=adj[v].begin(); iter!=adj[v].end(); iter++)
        {
            // 该物品未被访问过,且物品的等级在允许范围内
            if (!visited[iter->v] && (level_bottom<=V[iter->v].l && V[iter->v].l<=level_top))
            {
                int t = 0;
                t= dfs(iter->v, max(level_bottom, V[iter->v].l-m), min(level_top, V[iter->v].l+m));
                
                if (money > t+iter->off_price)
                    money = t+iter->off_price;
            }
        }

        visited[v] = false; // 退出清空该标志
        
        return money;
    }
}

int main()
{
    scanf("%d%d", &m, &n);

    for (int i=1; i<=n; i++)
    {
        int x = 0;
        scanf("%d%d%d", &V[i].price, &V[i].l, &x); // 建立点

        SUB_OBJ_S stSubObj; 
        for (int j=0; j<x; j++)
        {
            scanf("%d%d", &stSubObj.v, &stSubObj.off_price);
            adj[i].push_back(stSubObj); // 建立边
        }
    }

    printf("%d\n", dfs(1, V[1].l-m, V[1].l+m));
    
    return 0;
}

/*
    测试数据1:
    1 4
    10000 3 2
    2 8000
    3 5000
    1000 2 1
    4 200
    3000 2 1
    4 200
    50 2 0

    5250

    测试数据2:
    1 5
    10000 3 4
    2 3000
    3 2000
    4 2000
    5 9000
    8000 2 3
    3 5000
    4 2000
    5 7000
    5000 1 0
    2000 4 1
    5 1900
    50 1 0

    4000
    测试数据3:
    3 8
    10000 3 6
    2 3000
    3 2000
    4 2000
    5 9000
    7 1000
    8 5008
    8000 2 3
    3 5000
    4 2000
    5 7000
    5000 1 1
    6 1000
    2000 4 1
    5 1900
    50 1 0
    5000 1 1
    7 4007
    2000 4 1
    5 1900
    80 3 0

    2950
    测试数据4:
    1 10
    1324 0 0
    1234 0 0
    255 0 0
    67 0 0
    56 0 0
    2134 0 0
    456 0 0
    2345 0 0
    67 0 0
    6436 0 0

    1324

    测试数据5:
    1 4
    10000 3 2
    2 1
    3 3
    1000 2 2
    4 1
    3 1
    1000 3 1
    4 2
    100 4 0

    105
    测试数据6:
    3 5
    10000 3 4
    2 3000
    3 2000
    4 2000
    5 9000
    8000 2 3
    3 5000
    4 2000
    5 7000
    5000 1 0
    2000 4 1
    5 1900
    50 1 0

    3950
    测试数据7:
    0 5
    10000 3 4
    2 3000
    3 2000
    4 2000
    5 9000
    8000 2 3
    3 5000
    4 2000
    5 7000
    5000 4 0
    2000 3 1
    5 1900
    50 2 0

    4000
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值