POJ 1010 STAMPS

来源:互联网 发布:寒门崛起抄袭软件 编辑:程序博客网 时间:2024/05/18 02:20

又是一道经典搜索题,剪枝是必须的!

题意有点晦涩,参考了网上提供的中文版才明白过来到底是个什么事。

具体题意可参考http://blog.csdn.net/sdj222555/article/details/7240991这篇博文,同时也给出了用经典DFS模板写的代码。

这里给出了个人所想的剪枝方法:

1. 重点剪枝:由于题目中说明了不同类型的邮票可能具有相同的面值,所以这里把首先把邮票按面值大小进行排序,然后只保留面值不同的邮票,以及邮票面值相同时的邮票种类数。搜索组合方案时,暂时只考虑面值大小,不考虑邮票种类。
       如邮票种类:1 1 1 1 2 2 2 3 3 就可以表示为:(1, 4), (2, 3), (3, 2);
     要求找到面值总额为5的组合,那么搜索会考虑到这个组合:面值为1的需要3张,面值2的需要1张。事实上,面值1的邮票种类数有4张,为了使得最后的邮票种类数达到最大,应该使得组合中的3张面值为1的邮票种类不同。

2.  所需的面值总额小于最小的邮票面值时,停止

3. 邮票张数超过4,时,停止

这三个剪枝中,2,3是应题目要求,只有1是需要自己拿脑子来想想的。

附代码:

#include <iostream>#include <vector>#include <algorithm>using namespace std;class Answer{    public:int types;int number;int maxValue;vector<pair<int,int> > ans;Answer(int t=0, int n=0, int m=0):types(t), number(n), maxValue(m){};void assign(const vector<pair<int,int> >& temp, const vector<pair<int,int> >& stamps){    int i = 0;    while( temp[i].second && i < temp.size() )    {int j = temp[i].first;types += min(stamps[j].second, temp[i].second);number += temp[i].second;ans.push_back(pair<int, int>(j, temp[i].second));++i;    }    maxValue = stamps[ans.back().first].first;}int replace(const Answer& temp){    if(temp.types == types     && temp.number == number     && temp.maxValue == maxValue)return 0;    if(types > temp.types)return 1;    else if(types < temp.types)    {*this = temp;return -1;    }    if(number < temp.number)return 1;    else if(number > temp.number)    {*this = temp;return -1;    }    if(maxValue > temp.maxValue)return 1;    else if(maxValue < temp.maxValue)    {*this = temp;return -1;    }}void clear(){    types = number = maxValue = 0;    ans.clear();}};vector<pair<int, int> > stamps;Answer answer;vector<pair<int, int> > temp_ans;bool first, tie;void Work(int level, int pos, int need, int num){    if( !need )    {/*cout << "--------------------" << endl;for(int i = 0; i < temp_ans.size(); ++i){    int j = temp_ans[i].first;    cout << stamps[j].first << " " << temp_ans[i].second << endl;}cout << "--------------------" << endl;*///a solutionif( first ){    first = false;    answer.assign(temp_ans, stamps);}else {    Answer temp ;    temp.assign(temp_ans, stamps);    int r = answer.replace( temp );    if( !r )tie = true;    else if(tie && r == -1)tie = false;}return ;    }    if(num <= 0 || pos >= stamps.size() || level >= 4)return ;    if(need < stamps[pos].first)return;    int n = min(need/stamps[pos].first, num);    for(int i = 0; i <= n; ++i)    {int j = i>0?1:0;temp_ans[level] = pair<int,int>(pos, i);Work(level+j, pos+1, need-stamps[pos].first*i, num-i);temp_ans[level] = pair<int,int>(0, 0);    }}void Preprocess(vector<int>& v){    sort(v.begin(), v.end());    stamps.clear();    stamps.push_back( pair<int, int>(v[0], 1) );    int k = 0;    for(int i = 1; i < v.size(); ++i)    {if(stamps[k].first != v[i]){    stamps.push_back( pair<int,int>(v[i], 1) );    ++k;}else stamps[k].second += 1;    }}void JudgeTie(){    vector<pair<int,int> > v = answer.ans;    for(int i = 0; i < v.size(); ++i)    {int pos = v[i].first, num = v[i].second;int types = stamps[pos].second;if(types > 1 && num != types){    tie = true;    break;}    }}int main(){    int stamp;    while( cin >> stamp )    {vector<int> v;while( stamp ){    v.push_back( stamp );    cin >> stamp;}Preprocess( v );int minDemand = v.front();int maxDemand = v.back()*4;int demand;while( cin >> demand && demand ){    if( demand < minDemand || demand > maxDemand )    {cout << demand << " ---- none" << endl;continue;    }    first = true;    tie = false;    temp_ans.assign(4, pair<int,int>(0, 0));    answer.clear();    Work(0, 0, demand, 4);    if( first )    {cout << demand << " ---- none" << endl;continue;    }    JudgeTie();    if( tie )    {cout << demand << " (" << answer.types << "): tie" << endl;continue;    }    cout << demand << " (" << answer.types << "):";    vector<pair<int, int> > v = answer.ans;    for(int i = 0; i < v.size(); ++i)    {for(int k = 0; k < v[i].second; ++k)    cout << " " << stamps[v[i].first].first;    }    cout << endl;}    }    return 0;}