有 n 种巧克力,巧克力的4个属性:价格、保质期、数量、种类编号(id),每天吃一个巧克力,吃x天,如何花费最低    输入:第一行x,n,接下来n行巧克力的价格、保质期和数量   输出:最低价格

  1、算法分析:

  按价格从小到大排序,从第一天开始,每天吃一个巧克力,但是,巧克力有保质期,在后面可能没有在保质期内的巧克力可以吃了,这个思路走不通;

  按保质期从小到大排序,为了巧克力不过期,应从第一天开始,但是,保质期小,不一定是最低价格,这个思路也走不通;

  按保质期按从大到小排序,为了巧克力不过期,要从第x天开始(倒序),所有在第x天不过保质期的巧克力(种类)按价格从小到大进行排序可以选择第x天可以吃的最低价格的巧克力,同理,所有在第x-1天不过保质期的的巧克力(种类)按价格从小到大进行排序,可以选择第x-1天可以吃的最低价格的巧克力,...,所有在第1天不过保质期的的巧克力(种类)按价格从小到大进行排序,可以选择第1天可以吃的最低价格的巧克力,算法可行!

  2、算法C++实现:

  一、定义一个chocolate类,重载<运算符,用于类对象的直接比较大小(按保质期),定义一个函数对象类compare( 重载 () 运算符,两个chocolate类类型的参数 ),用于优先队列里的chocolate类对象比较大小(按价格)

  主函数:

  创建chocolate类类型的vector的对象vchoc,用于存储输入的n个chocolate类类型的对象,用sort对vector按保质期从大到小排序;创建chocolate类类型的优先队列,按价格从小到大排序;创建以chocolate类成员id为键的map容器,记录每天吃掉的巧克力

  在从第x天开始到第1天倒序的框架中(for循环),从vector复制在第i天在保质期内的所有种类的巧克力放入优先队列(只要放入就会按价格从小到大排序),在优先队列的队头就是最低价格的巧克力,也是在保质期内的巧克力,第i天吃掉一个,用map记录,同时累加吃掉的巧克力的价格,在队头的巧克力的数量与map记录的吃过的巧克力的数量对比,如果相等(该种巧克力吃完了),该队头从优先队列中剔除,注意:只要有巧克力放入优先队列或有巧克力出队,就会进行排序,所以,队头是动态变化的

  循环结束,打印累加的巧克力的价格即是最终结果

  在循环中,如果发现某天没有可以吃的巧克力(优先队列中没有chocolate类对象:q.size()==0 ),那么就是无解!

  使用vector下标:

#include <algorithm> 
#include <queue>
#include <map>
#include <vector>
#include <iostream>
using namespace std;

struct chocolate{
    long long a;  // 价格
    long long b;  // 保质期
    long long c;  // 数量
    int id;       // 种类
    bool operator<(const chocolate &choc){   //按保质期排序
        return b > choc.b;
    }
};

struct compare{
    bool operator()(const chocolate &choc1,const chocolate &choc2){   //priority_queue  按价格排序
        return choc1.a > choc2.a;
    }
};

int main()
{    
    freopen("d:\\1.txt","r",stdin );
    int x, n;           //n 种巧克力,吃 x 天
    long long TP = 0;   //总价 total price
    
    vector<chocolate > vchoc;     //存储各种巧克力,按保质期,用sort排序      //空vector,
    priority_queue<chocolate, vector<chocolate>, compare  > q; //按价格排序 //空队列
    map<int, long long > mp;  //键:巧克力种类id,值:为吃掉的该种巧克力的数量    //空map
    
    cin >> x >> n;
    for(int i=1; i<=n; ++i){ //n种巧克力,编号从 1 到 n
        chocolate t;
        t.id = i;               //编号
        cin>> t.a >> t.b >> t.c;//价格、保质期、数量      
        vchoc.push_back( t );
    }
                
    sort(vchoc.begin(),vchoc.end() );//按保质期排序

    for(int i=x,j=0; i>=1; i--)  //从第x天,到第一天
    {      
        while(j<vchoc.size() && vchoc[j].b>=i ){ //所有在该天(第i天),
            q.push(vchoc[j] );                     //在保质期内(vchoc[j].b>=i)的巧克力全部放入优先队列按价格排序,
            j++;                                 //可能会放入 >=0 且 <=n 种巧克力
        }
        
        if(!q.size()){
            cout << "-1" << endl;
            return 0;
        }
        
        chocolate t = q.top(); //取价格最小的巧克力
        mp[t.id]++;            //!!!以该种巧克力的编号为键,一天一个累加该种类的巧克力被吃掉的数量
        TP += t.a; //累加吃掉的巧克力的价格
        
        if(mp[t.id] == t.c ) {//!!!该种巧克力被吃完(被吃掉的数量 与 该种巧克力的数量相等)
             q.pop();    //从优先队列中剔除 
        }                    
    }
        
    cout << TP << endl;
        
    return 0; 
}


/* 10 3
1 6 5
2 7 3
3 10 10 */
View Code

  使用vector迭代器:

#include <algorithm> 
#include <queue>
#include <map>
#include <vector>
#include <iostream>
using namespace std;

struct chocolate{
    long long a;  // 价格
    long long b;  // 保质期
    long long c;  // 数量
    int id;       // 种类
    bool operator<(const chocolate &choc){   //按保质期排序
        return b > choc.b;
    }
};

struct compare{
    bool operator()(const chocolate &choc1,const chocolate &choc2){   //priority_queue  按价格排序
        return choc1.a > choc2.a;
    }
};

int main()
{    
    freopen("d:\\1.txt","r",stdin );
    int x, n;           //n 种巧克力,吃 x 天
    long long TP = 0;   //总价 total price
    
    vector<chocolate > vchoc;     //存储各种巧克力,按保质期,用sort排序      //空vector,
    priority_queue<chocolate, vector<chocolate>, compare  > q; //按价格排序 //空队列
    map<int, long long > mp;  //键:巧克力种类id,值:为吃掉的该种巧克力的数量    //空map
    
    cin >> x >> n;
    for(int i=1; i<=n; ++i){ //n种巧克力,编号从 1 到 n
        chocolate t;
        t.id = i;               //编号
        cin>> t.a >> t.b >> t.c;//价格、保质期、数量      
        vchoc.push_back( t );
    }
                
    sort(vchoc.begin(),vchoc.end() );//按保质期排序    
    vector<chocolate>::iterator it = vchoc.begin(); //vector迭代器

    for(int i=x; i>=1; i--)  //从第x天,到第一天
    {      
        while( it!=vchoc.end() && (it->b) >= i ){ //所有在该天(第i天),
            q.push(*it++ );                       //在保质期内( (it->b) >= i  )的巧克力全部放入优先队列按价格排序,
        }
        
        if(!q.size()){
            cout << "-1" << endl;
            return 0;
        }
        
        chocolate t = q.top(); //取价格最小的巧克力
        mp[t.id]++;            //!!!以该种巧克力的编号为键,一天一个累加该种类的巧克力被吃掉的数量
        TP += t.a; //累加吃掉的巧克力的价格
        
        if(mp[t.id] == t.c ) {//!!!该种巧克力被吃完(被吃掉的数量 与 该种巧克力的数量相等)
             q.pop();    //从优先队列中剔除 
        }                    
    }
        
    cout << TP << endl;
        
    return 0; 
}


/* 10 3
1 6 5
2 7 3
3 10 10 */
View Code

  二、定义一个chocolate类,重载<运算符,用于类对象的直接比较大小(按保质期),重载>运算符(友元函数,用于优先队列里的chocolate类对象比较大小(按价格))

  主函数:

  优先队列的第三个参数:greater<chocolate>

  使用vector下标:

#include <algorithm> 
#include <queue>
#include <map>
#include <vector>
#include <iostream>
using namespace std;

struct chocolate{
    long long a;  // 价格
    long long b;  // 保质期
    long long c;  // 数量
    int id;       // 种类
    bool operator<(const chocolate &choc){   //按保质期排序
        return b > choc.b;
    }
    friend bool operator>(const chocolate &choc1,const chocolate &choc2){  //priority_queue  按价格排序
        return choc1.a > choc2.a;
    }
};

int main()
{    
    freopen("d:\\1.txt","r",stdin );
    int x, n;           //n 种巧克力,吃 x 天
    long long TP = 0;   //总价 total price
    
    vector<chocolate > vchoc;     //存储各种巧克力,按保质期,用sort排序      //空vector,
    priority_queue<chocolate, vector<chocolate>, greater<chocolate>  > q; //按价格排序 //空队列
    map<int, long long > mp;  //键:巧克力种类id,值:为吃掉的该种巧克力的数量    //空map
    
    cin >> x >> n;
    for(int i=1; i<=n; ++i){ //n种巧克力,编号从 1 到 n
        chocolate t;
        t.id = i;               //编号
        cin>> t.a >> t.b >> t.c;//价格、保质期、数量      
        vchoc.push_back( t );
    }
                
    sort(vchoc.begin(),vchoc.end() );//按保质期排序

    for(int i=x,j=0; i>=1; i--)  //从第x天,到第一天
    {      
        while(j<vchoc.size() && vchoc[j].b>=i ){ //所有在该天(第i天),
            q.push(vchoc[j] );                     //在保质期内(vchoc[j].b>=i)的巧克力全部放入优先队列按价格排序,
            j++;                                 //可能会放入 >=0 且 <=n 种巧克力
        }
        
        if(!q.size()){
            cout << "-1" << endl;
            return 0;
        }
        
        chocolate t = q.top(); //取价格最小的巧克力
        mp[t.id]++;            //!!!以该种巧克力的编号为键,一天一个累加该种类的巧克力被吃掉的数量
        TP += t.a; //累加吃掉的巧克力的价格
        
        if(mp[t.id] == t.c ) {//!!!该种巧克力被吃完(被吃掉的数量 与 该种巧克力的数量相等)
             q.pop();    //从优先队列中剔除 
        }                    
    }
        
    cout << TP << endl;
        
    return 0; 
}


/* 10 3
1 6 5
2 7 3
3 10 10 */
View Code

   使用vector迭代器:

#include <algorithm> 
#include <queue>
#include <map>
#include <vector>
#include <iostream>
using namespace std;

struct chocolate{
    long long a;  // 价格
    long long b;  // 保质期
    long long c;  // 数量
    int id;       // 种类
    bool operator<(const chocolate &choc){   //按保质期排序
        return b > choc.b;
    }
    friend bool operator>(const chocolate &choc1,const chocolate &choc2){  //priority_queue  按价格排序
        return choc1.a > choc2.a;
    }
};

int main()
{    
    freopen("d:\\1.txt","r",stdin );
    int x, n;           //n 种巧克力,吃 x 天
    long long TP = 0;   //总价 total price
    
    vector<chocolate > vchoc;     //存储各种巧克力,按保质期,用sort排序      //空vector,
    priority_queue<chocolate, vector<chocolate>, greater<chocolate>  > q; //按价格排序 //空队列
    map<int, long long > mp;  //键:巧克力种类id,值:为吃掉的该种巧克力的数量    //空map
    
    cin >> x >> n;
    for(int i=1; i<=n; ++i){ //n种巧克力,编号从 1 到 n
        chocolate t;
        t.id = i;               //编号
        cin>> t.a >> t.b >> t.c;//价格、保质期、数量      
        vchoc.push_back( t );
    }
                
    sort(vchoc.begin(),vchoc.end() );//按保质期排序
    vector<chocolate>::iterator it = vchoc.begin(); //vector迭代器

    for(int i=x; i>=1; i--)  //从第x天,到第一天
    {      
        while( it!=vchoc.end() && (it->b) >= i ){ //所有在该天(第i天),
            q.push(*it++ );                       //在保质期内( (it->b) >= i  )的巧克力全部放入优先队列按价格排序,
        }
        
        if(!q.size()){
            cout << "-1" << endl;
            return 0;
        }
        
        chocolate t = q.top(); //取价格最小的巧克力
        mp[t.id]++;            //!!!以该种巧克力的编号为键,一天一个累加该种类的巧克力被吃掉的数量
        TP += t.a; //累加吃掉的巧克力的价格
        
        if(mp[t.id] == t.c ) {//!!!该种巧克力被吃完(被吃掉的数量 与 该种巧克力的数量相等)
             q.pop();    //从优先队列中剔除 
        }                    
    }
        
    cout << TP << endl;
        
    return 0; 
}


/* 10 3
1 6 5
2 7 3
3 10 10 */
View Code

   三、算法抽象

#include <algorithm> 
#include <queue>
#include <map>
#include <vector>
#include <iostream>
using namespace std;

struct chocolate{
    long long a;  // 价格
    long long b;  // 保质期
    long long c;  // 数量
    int id;       // 种类
    bool operator<(const chocolate &choc){   //按保质期排序
        return b > choc.b;
    }
    friend bool operator>(const chocolate &choc1,const chocolate &choc2){  //priority_queue  按价格排序
        return choc1.a > choc2.a;
    }
};

class eat_chocolate{
private:
    int x, n;       //n 种巧克力,吃 x 天
    long long TP;   //总价 total price 
    vector<chocolate > vchoc;     //存储各种巧克力,按保质期,用sort排序      //空vector,
    priority_queue<chocolate, vector<chocolate>, greater<chocolate>  > q; //按价格排序 //空队列
    map<int, long long > mp;  //键:巧克力种类id,值:为吃掉的该种巧克力的数量    //空map
    
    void input(){
        freopen("d:\\1.txt","r",stdin );
        cin >> x >> n;
        for(int i=1; i<=n; ++i){ //n种巧克力,编号从 1 到 n
            chocolate t;
            t.id = i;               //编号
            cin>> t.a >> t.b >> t.c;//价格、保质期、数量      
            vchoc.push_back( t );
        }
    }
    
public:
    eat_chocolate():x(0),n(0),TP(0){
        input();
    }    
    void run()//算法实现
    {  
        sort(vchoc.begin(),vchoc.end() );                //按保质期排序
        vector<chocolate>::iterator it = vchoc.begin(); //vector迭代器
        for(int i=x; i>=1; i--)  //从第x天,到第一天
        {      
            while( it!=vchoc.end() && (it->b) >= i ){   //所有在该天(第i天),
                q.push(*it++ );                         //在保质期内( (it->b) >= i  )的巧克力全部放入优先队列按价格排序,
            }
            
            if(!q.size()){
                cout << "-1" << endl;
                return;
            }
            
            chocolate t = q.top(); //取价格最小的巧克力
            mp[t.id]++;            //!!!以该种巧克力的编号为键,一天一个累加该种类的巧克力被吃掉的数量
            TP += t.a; //累加吃掉的巧克力的价格
            
            if(mp[t.id] == t.c ) {//!!!该种巧克力被吃完(被吃掉的数量 与 该种巧克力的数量相等)
                 q.pop();    //从优先队列中剔除 
            }                    
        }            
        cout << TP << endl;
    }
};

int main()
{                   
    eat_chocolate ec;
    ec.run();   
        
    return 0; 
}


/* 10 3
1 6 5
2 7 3
3 10 10 */
View Code

  不用 map,利用 vector 的副本计数

#include <algorithm> 
#include <queue>
#include <map>
#include <vector>
#include <iostream>
using namespace std;

struct chocolate{
    long long a;  // 价格
    long long b;  // 保质期
    long long c;  // 数量
    int id;
    
    bool operator<(const chocolate &choc){   //按保质期排序
        return b > choc.b;
    }
    friend bool operator>(const chocolate &choc1,const chocolate &choc2){  //priority_queue  按价格排序
        return choc1.a > choc2.a;
    }
};

class eat_chocolate{
private:
    int x, n;       //n 种巧克力,吃 x 天
    long long TP;   //总价 total price 
    vector<chocolate > vchoc;     //存储各种巧克力,按保质期,用sort排序      //空vector,
    priority_queue<chocolate, vector<chocolate>, greater<chocolate>  > q; //按价格排序 //空队列
    
    void input(){
        freopen("d:\\1.txt","r",stdin );
        cin >> x >> n;
        for(int i=1; i<= n; ++i){ //n种巧克力,编号从 1 到 n
            chocolate t;
            t.id = i;
            cin>> t.a >> t.b >> t.c;//价格、保质期、数量      
            vchoc.push_back( t );
        }
    }
    
public:
    eat_chocolate():x(0),n(0),TP(0){
        input();
    }
    
    void run()//算法实现
    {  
        vector<chocolate > vt = vchoc;                  //vector排序前的副本(id是有序的 )
        sort(vchoc.begin(),vchoc.end() );                //按保质期排序
        vector<chocolate>::iterator it = vchoc.begin(); //vector迭代器
        for(int i=x; i>=1; i--)  //从第x天,到第一天
        {      
            while( it!=vchoc.end() && (it->b) >= i ){   //所有在该天(第i天),
                q.push(*it++ );                         //在保质期内( (it->b) >= i  )的巧克力全部放入优先队列按价格排序,
            }
            
            if(!q.size()){
                cout << "-1" << endl;
                return;
            }
            
            chocolate t = q.top(); //取价格最小的巧克力
            TP += t.a; //累加吃掉的巧克力的价格
            
            if(0 == --vt[t.id-1 ].c ) {  //利用vector副本吃掉巧克力
                 q.pop();    //!!!该种巧克力被吃完,从优先队列中剔除 
            }          
        }            
        cout << TP << endl;
    }
};

int main()
{                   
    eat_chocolate ec;
    ec.run();   
        
    return 0; 
}


/* 10 3
1 6 5
2 7 3
3 10 10 */
View Code

  如果去掉 chocolate 的 id 属性,不用map计数,可以直接修改优先队列

#include <algorithm> 
#include <queue>
#include <map>
#include <vector>
#include <iostream>
using namespace std;

struct chocolate{
    long long a;  // 价格
    long long b;  // 保质期
    long long c;  // 数量

    bool operator<(const chocolate &choc){   //按保质期排序
        return b > choc.b;
    }
    friend bool operator>(const chocolate &choc1,const chocolate &choc2){  //priority_queue  按价格排序
        return choc1.a > choc2.a;
    }
};

class eat_chocolate{
private:
    int x, n;       //n 种巧克力,吃 x 天
    long long TP;   //总价 total price 
    vector<chocolate > vchoc;     //存储各种巧克力,按保质期,用sort排序      //空vector,
    priority_queue<chocolate, vector<chocolate>, greater<chocolate>  > q; //按价格排序 //空队列
    
    void input(){
        freopen("d:\\1.txt","r",stdin );
        cin >> x >> n;
        for(int i=1; i<=n; ++i){ //n种巧克力,编号从 1 到 n
            chocolate t;
            cin>> t.a >> t.b >> t.c;//价格、保质期、数量      
            vchoc.push_back( t );
        }
    }
    
public:
    eat_chocolate():x(0),n(0),TP(0){
        input();
    }
    
    void run()//算法实现
    {  
        sort(vchoc.begin(),vchoc.end() );                //按保质期排序
        vector<chocolate>::iterator it = vchoc.begin(); //vector迭代器
        for(int i=x; i>=1; i--)  //从第x天,到第一天
        {      
            while( it!=vchoc.end() && (it->b) >= i ){   //所有在该天(第i天),
                q.push(*it++ );                         //在保质期内( (it->b) >= i  )的巧克力全部放入优先队列按价格排序,
            }
            
            if(!q.size()){
                cout << "-1" << endl;
                return;
            }
            //因为反复的pop、push、排序,应该不如加上map来计数更好
            chocolate t = q.top(); //因为队头是const的不可以修改
            q.pop();               //因此要pop后再push进去 //有巧克力无剩余pop的含义
            if(t.c ){       //巧克力的数量不为0               
                TP += t.a; //累加吃掉的巧克力的价格
                if(--t.c ){//吃一个巧克力还剩余    
                    q.push(t ); //再push进去
                }                 
            }           
        }            
        cout << TP << endl;
    }
};

int main()
{                   
    eat_chocolate ec;
    ec.run();   
        
    return 0; 
}


/* 10 3
1 6 5
2 7 3
3 10 10 */
View Code