poj-1062(昂贵的婚礼)

前两天集训的时候现场赛考到这道题,一开始看到是中文的,心里那个激动啊,简直难以言表,然后我就埋头看了一下题,几分钟后,心里千万只草泥马在奔腾,这题在讲什么鬼,没看懂,这种感觉简直难以言表。赶紧切题,最后到比赛结束还是没想出来。过了两天,重新看这道题,好像有点明白了,个人感觉这道题相当不错。

题目大意:这道题虽然是中文题,但有些地方需要理解一下。总共有 N 个物品,对着N个物品从 1 到 N 编号,每个物品有 X 个替代品,比如样例所给的 1 号物品有两个替代品,其中一个编号为 2,表示用 2 号物品再加上8000元可以得到 1 号物品,其它类似(当初看到样例愣是没想到有什么联系敲打)。然后题目问最少用多少金币可以得到1号物品,注意题目中有一个等级限制,比如样例所给酋长的等级是 3 ,等级限制是 1,首先需要肯定你一定要跟酋长交易,所以样例所给的等级限制是2~3 和 3~4两种情况。附链接:http://poj.org/problem?id=1062

大体思路:这道题一旦理解清楚了,应该也能想到这是最短路问题(但题目一开始就很难理解)。因为可以 1 号物品有几种替代品,这里可以想象成从 1 出发有几条路可以到达某个结点 n,然后从 n 出发又有几条路可以到达其它地方,最后求的是从 1 出发到达其它各点最短的是多远。但题目有个限制就是等级,所以一开始可以将这些不满足等级限制的结点标识成已访问,这个问题就解决了。不过还有一个问题,就是怎么分类?这个可以将所有情况枚举,就样例所给的,先枚举等级 2~3 的情况,求出最短路后,再枚举等级 3~4 的情况,再求出最短路,然后两个最短路取最小输出。

以下是ac代码

#include<iostream>
#include<cstring>
using namespace std;

const int maxn=105;
const int inf=1e9;
int box[maxn][maxn];
int level[maxn];
int price[maxn];
int vis[maxn];
int n,m;

int dijkstra(int start){
    int dist[maxn];
    for(int i=1;i<=n;i++)  //这里需要注意,初始化为inf,不能为box[1][i],就因为这里wa两次,查了一个多小时
        dist[i]=inf;
    dist[1]=0;  //初始化为0,以便第一次循环从1开始
    for(int i=0;i<n;i++){
        int Min=inf,k=-1;
        for(int j=1;j<=n;j++)
            if(!vis[j]&&dist[j]<Min){
                Min=dist[j];
                k=j;
            }
        if(k==-1)
            break;
        vis[k]=1;
        for(int j=1;j<=n;j++)
            if(!vis[j]&&dist[j]>dist[k]+box[k][j])
                dist[j]=dist[k]+box[k][j];
    }
    int Min=inf;
    for(int i=1;i<=n;i++)     //计算最短路时,记得加上原先的价格
        Min=min(Min,price[i]+dist[i]);
    return Min;
}
int main(){
    while(cin>>m>>n){
        int k;
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                box[i][j]=inf;
        for(int i=1;i<=n;i++){
            cin>>price[i]>>level[i]>>k;
            for(int j=1;j<=k;j++){
                int a,b;
                cin>>a>>b;
                box[i][a]=b;
            }
        }
        int Min=inf;
        for(int i=0;i<=m;i++){   //枚举等级,一开始还担心超时。
            memset(vis,0,sizeof(vis));   //全部标识为未访问
            for(int j=1;j<=n;j++)
                if((level[1]-m+i)>level[j]||level[j]>(level[1]+i)) //等级之外标识为已访问
                    vis[j]=1;
            Min=min(Min,dijkstra(1));
        }
        cout<<Min<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值