M - 昂贵的聘礼


年轻的探险家来到了一个印第安部落里。在那里他和酋长的女儿相爱了,于是便向酋长去求亲。酋长要他用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


题目中文的这都不解释了( ̄▽ ̄)"。


分析:输入数据,假设你想要u,可以用v来换u但是还得多加钱数为money,那么就建立一条边v->u,边上的权为money
数量。
那么这条边的意思就是用v再加上money才能换到u。
又因为每个物品都有自己的编号,所以建立一系列这样的边从而形成一个图。(等级的限制问题一会就说)


我再加入一个“超级源点“(这是其他人说的,但是挺超级的)x ,设其编号为0
x->u的边权为u的价钱,那么重新生成的这个图。我们求0到1的最短路径即可。(等级限制的问题呢?,别急下面就说)


/*

题中  不同等级之间交易限制的问题,是个难处理的地方。
为了方便处理可以枚举每种可能性,然后从中找出答案
每次枚举编号中的其中一个,假设它为0->1最短路中等级最低
的一个人物v,那么在找最短路上,必须保证交易的过程中
每个的等级都可以与v交易,且等级都大于v(前面说了v等级最低),否则不能交易(INF)
然后求0->1(0作为超级源点)的最短路径-----(这个交易过
程中满足题目要求)

又因为在答案的最短路中一定存在最低等级的人物v,使这条
交易线上的都满足这样的关系,那么从枚举的最短路径中选出最小的就
是我们要的答案
*/

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<math.h>//
#define N 110
#define INF 0x3fffffff
using namespace std;
int map[N][N],dis[N],rankk[N],book[N],m;//对应编号的等级
bool check(int a)//a->b等级之间能否交易//把超级源点0的等级比作此次最短路路径的最低等级
{
    if(rankk[a]<rankk[0]||(rankk[a]>rankk[0]+m))
        return 0;
    return 1;
}
void dijkstra(int n)
{
    int t=n;
    int minn,u,mid;
    while(t--)
    {
        minn=INF;
        for(int i=0;i<=n;i++)
        {
            if(!book[i]&&dis[i]<minn)
            {
                minn=dis[i];
                u=i;
            }
        }
        book[u]=1;
        if(!u)
            return ;
        for(int i=0;i<=n;i++)
        {
            if(!check(i))
              continue;
            mid=dis[u]+map[i][u];
            if(mid<dis[i])
                dis[i]=mid;
        }
    }
}
int main()
{
    int n,money,rr,tt,num,ans;
    scanf("%d %d",&m,&n);//共n个物品
    for(int i=0;i<=n;i++)
        for(int j=i+1;j<=n;j++)
           map[i][j]=map[j][i]=INF;
    for(int i=1;i<=n;i++)//表示这个物品的编号,
    {
        scanf("%d %d %d",&money,&rr,&tt);
        map[0][i]=money;//超级源点
        rankk[i]=rr;//第i的物品拥有者的等级是rr
        while(tt--)
        {
            scanf("%d %d",&num,&money);
            map[num][i]=money;
        }
    }
   ans=INF;
   for(int k=1;k<=n;k++)
   {
       rankk[0]=rankk[k];
       if(!check(1))//容易忽略的点... 当1与此人物的等级不能满足交易关系时,表明此次交易就不可能会成功,continue
         continue;
       for(int i=0;i<=n;i++)//update
       {
           book[i]=0;
           if(check(i))
            dis[i]=map[i][1];
           else
            dis[i]=INF;
       }
       dis[1]=0;
       book[1]=1;
       dijkstra(n);
       ans=dis[0]<ans?dis[0]:ans;
   }
    printf("%d\n",ans);
}



posted @ 2018-01-28 17:04  _年少有为  阅读(201)  评论(0编辑  收藏  举报