吃巧克力,容器vector、map,容器适配器 priority_queue,算法sort排序
Posted on 2023-03-27 22:27 金色的省略号 阅读(96) 评论(0) 编辑 收藏 举报有 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 */
使用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 */
二、定义一个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 */
使用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 */
三、算法抽象

#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 */
不用 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 */
如果去掉 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 */