题目链接:http://poj.org/problem?id=1062
Time Limit: 1000MS Memory Limit: 10000K

Description

年轻的探险家来到了一个印第安部落里。在那里他和酋长的女儿相爱了,于是便向酋长去求亲。酋长要他用10000个金币作为聘礼才答应把女儿嫁给他。探险家拿不出这么多金币,便请求酋长降低要求。酋长说:"嗯,如果你能够替我弄到大祭司的皮袄,我可以只要8000金币。如果你能够弄来他的水晶球,那么只要5000金币就行了。"探险家就跑到大祭司那里,向他要求皮袄或水晶球,大祭司要他用金币来换,或者替他弄来其他的东西,他可以降低价格。探险家于是又跑到其他地方,其他人也提出了类似的要求,或者直接用金币换,或者找到其他东西就可以降低价格。不过探险家没必要用多样东西去换一样东西,因为不会得到更低的价格。探险家现在很需要你的帮忙,让他用最少的金币娶到自己的心上人。另外他要告诉你的是,在这个部落里,等级观念十分森严。地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。他是一个外来人,所以可以不受这些限制。但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。因此你需要在考虑所有的情况以后给他提供一个最好的方案。 
为了方便起见,我们把所有的物品从1开始进行编号,酋长的允诺也看作一个物品,并且编号总是1。每个物品都有对应的价格P,主人的地位等级L,以及一系列的替代品Ti和该替代品所对应的"优惠"Vi。如果两人地位等级差距超过了M,就不能"间接交易"。你必须根据这些数据来计算出探险家最少需要多少金币才能娶到酋长的女儿。 

Input

输入第一行是两个整数M,N(1 <= N <= 100),依次表示地位等级差距限制和物品的总数。接下来按照编号从小到大依次给出了N个物品的描述。每个物品的描述开头是三个非负整数P、L、X(X < N),依次表示该物品的价格、主人的地位等级和替代品总数。接下来X行每行包括两个整数T和V,分别表示替代品的编号和"优惠价格"。

Output

输出最少需要的金币数。

Sample Input

1 4
10000 3 2
2 8000
3 5000
1000 2 1
4 200
3000 2 1
4 200
50 2 0

Sample Output

5250

Problem solving report:

Description: N个物品,每个物品的主人有等级,每个物品都有价格,某些物品也可以由一些物品替代,且等级差距小于M的两者不能直接和间接交易,一开始可以和任意人交易问怎么样选取可以让你的花费最少来购买到物品1。
Problem solving: 0号代表起点,1代表终点,就求0-->1的最短路。首先构造一个点0,表示探险家的编号,那么最后求的就是0到1的最短路径,其中根据题意知1是酋长的物品。然后对于每一件物品i(1<=i<=n),首先判断它跟1的等级差距是否小于等于m,否则直接continue,因为间接交易它是无法到达1的。然后对于该物品所能替代的物品k,要先判断k与1的等级差距以及k与x的等级差距,如果都满足小于等于m,则对k与i连单向边。最后做Dijkstra或者Spfa。松弛的时候要记录一下前驱,因为整个松弛过程都要满足等级差距不大于m,刚才对边的处理只是保证了每个点与1和它能替换的点的等级不大于m。样例构造图形见下图:

POJ - 昂贵的聘礼(最短路)_ACM题解

Accepted Code:

//Dijkstra
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 105;
const int inf = 0x3f3f3f3f;
struct edge {
    int val, lev, cal;
    int reg[MAXN], pri[MAXN];
}p[MAXN];
int n, m;
bool vis[MAXN];
int dis[MAXN], pre[MAXN], mp[MAXN][MAXN];
void Dijkstra(int s) {
    memset(pre, 0, sizeof(pre));
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, false, sizeof(vis));
    dis[s] = 0;
    for (int i = 1; i <= n; i++) {
        int min_ = inf, k = s;
        for (int j = 0; j <= n; j++)
            if (!vis[j] && dis[j] < min_)
                min_ = dis[k = j];
        vis[k] = true;
        for (int j = 0; j <= n; j++)
            if (!vis[j] && dis[j] > dis[k] + mp[k][j])
                if (!pre[k] || abs(p[pre[k]].lev - p[j].lev) <= m)
                    dis[j] = dis[k] + mp[k][j], pre[j] = k;
    }
}
int main() {
    while (~scanf("%d%d", &m, &n)) {
        for (int i = 1; i <= n; i++) {
            scanf("%d%d%d", &p[i].val, &p[i].lev, &p[i].cal);
            for (int j = 0; j < p[i].cal; j++)
                scanf("%d%d", &p[i].reg[j], &p[i].pri[j]);
        }
        memset(mp, 0x3f, sizeof(mp));
        for (int i = 1; i <= n; i++)
            mp[0][i] = p[i].val;
        for (int i = 1; i <= n; i++) {
            if (abs(p[i].lev - p[1].lev) <= m) {
                for (int j = 0; j < p[i].cal; j++) {
                    int reg = p[i].reg[j];
                    if (abs(p[i].lev - p[reg].lev) <= m && abs(p[reg].lev - p[1].lev) <= m) {
                        mp[reg][i] = p[i].pri[j];
                    }
                }
            }
        }
        Dijkstra(0);
        printf("%d\n", dis[1]);
    }
    return 0;
}
//Spfa
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 105;
const int inf = 0x3f3f3f3f;
struct edge {
    int val, lev, cal;
    int reg[MAXN], pri[MAXN];
}p[MAXN];
int n, m;
bool vis[MAXN];
int dis[MAXN], pre[MAXN], mp[MAXN][MAXN];
void Spfa(int s) {
    queue <int> Q;
    Q.push(s);
    memset(pre, 0, sizeof(pre));
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, false, sizeof(vis));
    dis[s] = 0;
    while (!Q.empty()) {
        int u = Q.front();
        Q.pop();
        vis[u] = false;
        for (int i = 0; i <= n; i++) {
            if (dis[i] > dis[u] + mp[u][i] && (!pre[u] || abs(p[pre[u]].lev - p[i].lev) <= m)) {
                dis[i] = dis[u] + mp[u][i];
                pre[i] = u;
                if (!vis[i]) {
                    Q.push(i);
                    vis[i] = true;
                }
            }
        }
    }
}
int main() {
    while (~scanf("%d%d", &m, &n)) {
        for (int i = 1; i <= n; i++) {
            scanf("%d%d%d", &p[i].val, &p[i].lev, &p[i].cal);
            for (int j = 0; j < p[i].cal; j++)
                scanf("%d%d", &p[i].reg[j], &p[i].pri[j]);
        }
        memset(mp, 0x3f, sizeof(mp));
        for (int i = 1; i <= n; i++)
            mp[0][i] = p[i].val;
        for (int i = 1; i <= n; i++) {
            if (abs(p[i].lev - p[1].lev) <= m) {
                for (int j = 0; j < p[i].cal; j++) {
                    int reg = p[i].reg[j];
                    if (abs(p[i].lev - p[reg].lev) <= m && abs(p[reg].lev - p[1].lev) <= m) {
                        mp[reg][i] = p[i].pri[j];
                    }
                }
            }
        }
        Spfa(0);
        printf("%d\n", dis[1]);
    }
    return 0;
}