首页 > 代码库 > poj1062 最短路(加限制)

poj1062 最短路(加限制)

http://poj.org/problem?id=1062

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
/**
poj 1062  带有限制的最短路(需要稍该模板)
题目大意:每个人都有一个物品,对应一定的钱数,想要得到此物品可以直接出钱,
          也可以通过用其他人的物品并添加一些钱来交换,问要得到酋长的物品最少需要多少钱?
          另外,每个人都有一个等级,要求和你交易的人中不能有任何两人的等级相差m以上。
解题思路:(转)我们可以把本题理解为,我们要买一号物品,而一个物品的一部分价值可以转化为别的物品,
          我们通过购买别的物品和加钱来购买获得一号物品。所以我们可以把需要加的钱数作为该物品到
          别的物品的一条边,走过这条边,我们要花一些钱,然后我们只需要购买现在所在结点的物品即可。
          这样就把问题转化为最短路问题,用dijkstra就可以了。关于等级限制的问题。我们可以每次枚举
          一个宽为m的等级区间,忽略不在区间内的点,进行spfa。
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <string.h>
#include <algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
const int maxm=5111;
const int maxn=111;

struct EdgeNode
{
    int to;
    int w;
    int next;
} edges[maxm];
int n,m;
int head[maxn],edge;
int a[maxn],ra[maxn];
bool vis[maxn];
int dis[maxn],dist[maxn],level[maxn];

void addedge(int u,int v,int c)
{
    edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}

void init()
{
    memset(head,-1,sizeof(head));
    edge=0;
}

void spfa(int floor)
{
    int s=0;
    int u;
    for (int i=0; i<=n; i++)
        dis[i]=INF;
    memset(vis,0,sizeof(vis));
    queue <int> que;
    que.push(s);
    vis[s]=true;
    dis[s]=0;
    while (!que.empty())
    {
        u=que.front();
        que.pop();
        vis[u]=false;
        for (int i=head[u]; i!=-1; i=edges[i].next)
        {
            int v=edges[i].to;
            int w=edges[i].w;
            if ((dis[v]>dis[u]+w )&&ra[v]>=floor && ra[v]<=floor+m)///满足等级在枚举的等级区间内
            {
                dis[v]=dis[u]+w;
                if (!vis[v])
                {
                    vis[v]=true;
                    que.push(v);
                }
            }
        }
    }
    for(int i=0; i<n; i++)
    {
        if(dist[i]>dis[i])
            dist[i]=dis[i];
    }
}

int main()
{
    while(~scanf("%d%d",&m,&n))
    {
        for(int i=0; i<=n; i++)
            dist[i]=INF;
        init();
        int levelnum=0;
        for(int i=0; i<n; i++)
        {
            int num;
            scanf("%d%d%d",&a[i],&ra[i],&num);
            level[levelnum++]=ra[i];
            for(int j=0; j<num; j++)
            {
                int w,x;
                scanf("%d%d",&x,&w);
                addedge(i,x-1,w);
            }
        }
        sort(level,level+levelnum);
        levelnum=unique(level,level+levelnum)-level;
        for(int i=0; i<levelnum; i++)
        {
            if(ra[0]>=level[i]&&ra[0]<=level[i]+m)
                spfa(level[i]);
        }
        int ans=INF;
        for(int i=0; i<n; i++)
        {
            ans=min(ans,dist[i]+a[i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}
/**
1 4
100 3 2
2 8000
3 5000
1000 2 1
4 200
3000 2 1
4 200
50 2 0

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

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

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

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

1 4
10000 3 2
2 8000
3 50000
1000 2 1
4 200
3000 2 1
4 200
50 12 0
*/


poj1062 最短路(加限制)