题目: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.