zoukankan      html  css  js  c++  java
  • poj1062

    昂贵的聘礼
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 44514   Accepted: 13115

    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

    Source

    题目大意:有N个物品,每个物品都有自己的价格,但同时某些物品也可以由其他的(可能不止一个)替代品,这些替代品的价格比较“优惠”,问怎么样选取可以让你的花费最少来购买到物品1

    由于有N个物品,我们就可以把它们看作是N个点,从其他点到他的优惠关系视做边,又因为最后总是要找到物品1,所以可以看作是从起点0,到将物品1作为终点的最小路径。然后由于题目是说,这条路径上不能有两个的等级差超过M,所以我们可以枚举最小等级,将每个点视作最小等级,这样的话就不会掉解。

    又由于我们是枚举的最小等级,所以源点0到其他每个点的边的权值就要赋值为那个点的价格,降等级比最小等级要大,或者差距大于M的其他点标记为不合法(也就是不可以走),然后在从合法的路径中找出最小花费。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define N 500
    #define inf 0x3fffffff
    int m,n;//M为等级差,N为物品数目
    int vis[N];
    int lev[N];//第i号物品主人的等级
    int dis[N];//最初的源点0到任意点i的最初距离(权值),相当于每个物品的原价 
    int map[N][N];//物品i在有第t号替代品情况下的优惠价map[t][i],当t=0时说明i无替代品,此时为原价
    int dijkstra(int v0,int l,int r){
        for(int i=0;i<=n;i++) dis[i]=map[v0][i];//物品i在有第v0号替代品情况下的优惠价,即点v0到点i的权值 
        dis[v0]=0;
        vis[v0]=1;
        for(int i=1;i<=n;i++){//由于1点是目标点,因此最坏的打算是进行n次寻找源点到其他点的最短路,并合并这两点(不再访问相当于合并了)
            int u,mi=inf;//在for里面定义容易出错误,以后要注意 
            for(int j=0;j<=n;j++){
                if(!vis[j]&&dis[j]<mi){
                    mi=dis[j];
                    u=j;
                }
            }
            vis[u]=1;//当其它物品j的等级比当前物品高(保证单向性),并且两者等级之差超出限制M时:物品j则强制定义为“已访问”状态,不参与后续操作 
            for(int j=0;j<=n;j++){//反之,则可以更新 
                if(!vis[j]&&lev[j]<=r&&lev[j]>=l&&lev[u]<=r&&lev[u]>=l){
                    dis[j]=min(dis[j],dis[u]+map[u][j]);
                }
            }
        }
        for(int i=0;i<=n;i++) vis[i]=0;
        return dis[1];//返回当前次交易后目标点1在等级lev[i]约束下的最短距离
    }
    int main(){
        scanf("%d%d",&m,&n);
        for(int i=0;i<=n;i++){
            for(int j=0;j<=n;j++){
                map[i][j]=(i==j?0:inf);
            }
        }
        for(int i=1,x;i<=n;i++){
            scanf("%d%d%d",&map[0][i],&lev[i],&x);
            for(int j=1,t,v;j<=x;j++){
                scanf("%d%d",&t,&v);
                map[t][i]=v;//物品i在有第t号替代品情况下的优惠价,即点t到点i的权值 
            }
        }
        int ans=inf;//记录当前次交易后目标点1在等级lev[i]约束下的最短距离(最少价格)
        for(int i=lev[1]-m;i<=lev[1];i++){//寻找各次交易后的最少价格,最终确认最少价格
            ans=min(ans,dijkstra(0,i,i+m));
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    I Hate It
    满减优惠[Offer收割]编程练习赛4
    积水的城市 hiho[Offer收割]编程练习赛4
    Subsequence 尺取法
    526. 优美的排列
    401. 二进制手表
    306. 累加数
    216. 组合总和 III
    131. 分割回文串
    ubuntu deepin-软件 分辨率的问题
  • 原文地址:https://www.cnblogs.com/shenben/p/5627235.html
Copyright © 2011-2022 走看看