【hdoj_1015】Safecracker(排列组合)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1015

题意:从给定的几个元素选择出符合5个组成一个组合,输出字典序的最后一个符合要求的组合,如果不存在符合要求的组合,则输出"no solution".


从若干元素中选择出5个元素,初看是组合问题,其实不是,因为组合问题选择出来的组合没有顺序的要求,如[X Z U B A]和[U X B A Z]是一个组合,但是对于本题来说,这两种组合是不同的,因为选择出来的如何和[v,w,x,y,z]对应,即v,w,x,y,z分别是多少有5!中可能,所以本题不是简单的组合问题,二是组合+排列问题,可以在全排列问题的基础上求解.


代码如下:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

int target;
string s;
int a[100];
int b[10]; 
int vis[100];

int n,k;
int flag;

void dfs(int cur)
{
	if(cur==k+1)//已经选择了k个数字
	{
		int sum = b[1] - b[2]*b[2] + b[3]*b[3]*b[3] - b[4]*b[4]*b[4]*b[4] + b[5]*b[5]*b[5]*b[5]*b[5];
		if(sum==target)//判断是否满足要求
			flag = 1;
		return;//无论如何,此次递归结束,一定要加这句话,否则超时
	}

	for(int i=n;i>=1;i--)//从后面开始,以满足[输出字典序最后一个]的要求
	{
		if(!vis[i])
		{
			vis[i] = 1;//标记已经访问过了
			b[cur] = a[i];
			dfs(cur+1);
			if(flag) return;//看看是否有必要回溯:如果已经成功了,则直接退出
			vis[i] = 0;//回溯
		}
	}
}

int main()
{
	while(1)
	{
		cin >> target >> s;
		if(target==0 && s.compare("END")==0)
			break;
		n = s.length();
		for(int i=1;i<=n;i++)
		{
			a[i] = s[i-1]-'A'+1;//转化为对应数字
			vis[i] = 0;//标记数组初始化
		}
		sort(a+1,a+n+1);//排序,注意a[1~n]的下标是从1开始的
		flag = 0;
		k = 5;
		dfs(1);
		if(flag)
		{
			for(int i=1;i<=k;i++)
			{
				char x = b[i]+'A'-1;//转化为字符
				cout << x;
			}
			cout << endl;
		}
		else
			cout << "no solution" << endl;
	}

	return 0;
}
上述代码提交,可以通过.


注意:在判断递归边界的时候,一定要return,标志此次递归的结束,否则,有可能不知道什么时候结束此次递归,从而造成超时.所以,在上述代码中,处理递归边界的时候,无论是否找到满足要求的解,都要return.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值