poj 1062 昂贵的聘礼

来源:互联网 发布:嵌入式软件 启动过程 编辑:程序博客网 时间:2024/06/05 09:10

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

浙江

**声明:引自“優YoU”
地址:http://user.qzone.qq.com/289065406/blog/1299338542**

/*Problem: 1062  User: saruka Memory: 760K  Time: 32MS Language: G++  Result: Accepted */#include<iostream>   #include<cstring>using namespace std; const int INF = 1009999999;const int maxn = 105;int M, N;int price[maxn][maxn], lv[maxn], x[maxn], dis[maxn]; bool vis[maxn];/*    M为等级差,N为物品数目    物品i在有第t号替代品情况下的优惠价 pricr[t][i], 当 t = 0 时说明i无替代品,此时为原价    第i号物品主人的等级为 lv[i]    第i号物品的替代品总数为 x[i]    dis[i]最初的源点0到任意点i的最初距离(权值),相当于每个物品的原价    vis[i] 记录点i是否已被访问*/void data_init()   {       memset(price, 0, sizeof(price));       memset(lv, 0, sizeof(lv));       memset(dis, INF, sizeof(dis));       memset(vis, false, sizeof(vis));      cin >> M >> N;       for(int i = 1; i <= N; i++)       {           cin >> price[0][i] >> lv[i] >> x[i];        /*price[0][i]物品i无替代品时的原价*/        for(int j = 1; j <= x[i]; j++)           {               int t, u;            /*t替代品编号,u优惠价(临时变量)*/            cin >> t >> u;            price[t][i] = u;            /*物品i在有第t号替代品情况下的优惠价,即点t到点i的权值*/        }       }   }   int dijkstra()   {       int node, sd, i, j;    /*    node记录与当前源点距离最短的点    sd记录最短距离    */    for(i = 1; i <= N; i++)    {        dis[i] = price[0][i];        /*假设最初的源点就是0点,初始化最初源点到各点的权值dist[i]*/    }    for(i = 1; i <= N; i++)    {           /*由于1点是目标点,因此最坏的打算是进行n次寻找源点到其他点的最短路,并合并这两点(不再访问相当于合并了)*/        node = 0;           sd = INF;           for(j = 1; j <= N; j++)           {               if(!vis[j] && sd > dis[j])            {                sd = dis[j];                   node = j;            }           }           if(node == 0) break;        /*若node没有变化,说明所有点都被访问,最短路寻找完毕*/        vis[node] = true;        for(j = 1; j <= N; j++)           {               if(!vis[j] && price[node][j] > 0 && dis[j] > dis[node] + price[node][j])            {                /*把未访问但与node(新源点)连通的点进行松弛*/                dis[j] = dis[node] + price[node][j];               }        }    }       return dis[1];    /*返回当前次交易后目标点1在等级lv[i]约束下的最短距离*/} int main(){    data_init();    int temp_price, maxlv, minprice = INF;    /*    temp_price当前次交易后目标点1在等级lv[i]约束下的最少价格    maxlv最大等级(酉长的等级不一定是最大的)    minprice最低价格(初始化为无限大)    */    for(int i = 1; i <= N; i++)       {           /*在等级限制下,寻找允许被当前点访问的点*/         maxlv = lv[i];        /*把当前物品的等级暂时看做最高等级*/        for(int j = 1; j <= N; j++)        {               if(lv[j] > maxlv || maxlv - lv[j] > M)            /*当其它物品j的等级比当前物品高(保证单向性),或者两者等级之差超出限制 M 时*/            {                vis[j] = true;            }               else            {                vis[j] = false;            }            }        temp_price = dijkstra();        /*记录当前次交易后目标点1在等级lv[i]约束下的最短距离(最少价格)*/        if(minprice > temp_price)        {            minprice = temp_price;        }       }       cout << minprice << endl;       return 0;}

当然,还有看起来更工整的算法。
引自一位神犇“lin375691011”的博客“poj 训练纪实”。
戳一下:http://blog.csdn.net/column/details/linway.html?&page=1
算法如下:

/*Problem: 1062       User: sarukaMemory: 404K        Time: 63MSLanguage: G++       Result: Accepted*/#include <cstdio>const int V = 105;const int E = 10005;struct node {    int mon, lv;} wu[V];struct node1 {    int u, v, w;} edge[E];int m, l, r, dis[V], vis[V];void bellmam_ford(int n){    int flat;    for(int i = 0; i < n; i++)  //初始化0点到各点的权值,及各物品的价值,dis[0]=0。    {        dis[i] = wu[i].mon;    }    flat = 0;    for(int i = 1; i <= n; i++)    {        for(int j = 0; j < m; j++)        {            if(wu[edge[j].u].lv >= l && wu[edge[j].u].lv <= r && wu[edge[j].v].lv >= l && wu[edge[j].v].lv <= r && dis[edge[j].u] > dis[edge[j].v] + edge[j].w)            {                dis[edge[j].u] = dis[edge[j].v] + edge[j].w;                flat = 1;            }        }        if(!flat) break;    }}int main(){    int M, N;    while(scanf("%d%d", &M, &N) != EOF)    {        int t;        m = 0;        for(int i = 1; i <= N; i++) //进行输入,建立有向边的邻接表。        {            scanf("%d%d%d", &wu[i].mon, &wu[i].lv, &t);            edge[m].u = 0;            edge[m].v = i;            edge[m].w = wu[i].mon;            m++;            for(int j = 0; j < t; j++)            {                scanf("%d%d", &edge[m].v, &edge[m].w);                edge[m].u = i;                m++;            }        }        int min1 = wu[1].mon;        wu[0].lv = wu[1].lv;        for(l = wu[1].lv - M; l <= wu[1].lv; l++)   //枚举等级范围,范围长度为M。        {            r = l + M;            bellmam_ford(N + 1);    //因为多虚拟一个点,所以是n+1个点            if(min1 > dis[1])            {                min1 = dis[1];            }        }        printf("%d\n", min1);    }    return 0;}

Powered By Saruka.
Copyright © 2016 All Rights Reserved.

0 0
原创粉丝点击