POJ 1010 STAMPS

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

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

具体题意可参考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 solution
	if( 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值