POJ 1062 昂贵的聘礼(图论,最短路径)

POJ 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

Http

POJ:https://vjudge.net/problem/POJ-1062

Source

图论,动态规划

解决思路

首先是如何建图。
对于一个优惠如果用B来换A可以优惠到C元,我们连边B->A,边权为C。注意是有向边。那么我们在跑最短路的时候所有的初值都是其原价,最后跑出的到一的距离即为所求。
但由于本题有等级的限制,如果直接把限制条件加在最短路的松弛条件中会漏情况。解决方案是依次枚举每一个点,把其等级作为最高等级,然后把等级高于它或等级差大于M的点强制设置为已经经过,及Dijkstra里不再松弛,这样就可以了。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxN=101;
const int maxM=maxN*maxN;
const int inf=2147483647;

int n,M;
class Graph//为了方便操作,封装在类里
{
private:
    int cnt;
    int Head[maxN];
    int Next[maxM];
    int V[maxM];
    int W[maxM];
    bool vis[maxN];
public:
    int n;
    int Dist[maxN];
    int Value[maxN];//原价
    int Status[maxN];//等级
    void init()//初始化
    {
        cnt=0;
        memset(Head,-1,sizeof(Head));
        memset(Next,-1,sizeof(Next));
        memset(Dist,127,sizeof(Dist));
    }
    void Add_Edge(int u,int v,int w)//加边
    {
        cnt++;
        Next[cnt]=Head[u];
        Head[u]=cnt;
        V[cnt]=v;
        W[cnt]=w;
    }
    int Dijkstra()//Dijkstra过程
    {
        for (int i=1;i<=n;i++)
            Dist[i]=Value[i];
        for (int i=1;i<n;i++)
        {
            int id=-1,mi=inf;
            for (int j=1;j<=n;j++)
                if ((vis[j]==0)&&(Dist[j]<mi))
                {
                    mi=Dist[j];
                    id=j;
                }
            if (id==-1)
                break;
            vis[id]=1;
            for (int i=Head[id];i!=-1;i=Next[i])
            {
                if ((vis[V[i]]==0)&&(Dist[V[i]]>Dist[id]+W[i]))
                {
                    Dist[V[i]]=Dist[id]+W[i];
                }
            }
        }
        return Dist[1];
    }
    int work()//用work来调用Dijkstra,每次枚举最高等级,然后强制某些点不走
    {
        int Ans=inf;//记录最优答案
        for (int i=1;i<=n;i++)
        {
            int maxlv=Status[i];
            memset(vis,0,sizeof(vis));//注意每次先置0
            for (int j=1;j<=n;j++)
                if ((Status[j]>maxlv)||(maxlv-Status[j]>M))//大于当前最高等级或等级之差大于M的强制不松弛
                    vis[j]=1;
            Ans=min(Ans,Dijkstra());//用当前图更新最佳的答案
        }
        return Ans;
    }
};

Graph G;

int main()
{
    G.init();
    cin>>M>>n;
    G.n=n;
    for (int i=1;i<=n;i++)
    {
        cin>>G.Value[i]>>G.Status[i];
        int tot;
        cin>>tot;
        for (int j=1;j<=tot;j++)
        {
            int u,w;
            cin>>u>>w;
            G.Add_Edge(u,i,w);
        }
    }
    cout<<G.work()<<endl;
    return 0;
}
posted @ 2017-07-24 20:13 SYCstudio 阅读(...) 评论(...) 编辑 收藏