一:题目
给定k个正整数,用算术运算符+,-,,/ 将这k个正整数连接起来,是最终的得数恰为m。
如果有多组满足要求的表达式,只要输出一组,每一步算式用分号隔开。
如果无法得到m,得输出“No Solution”。
样例输入:d
5 125
7 2 2 12 3
第一行输入整数的个数k和m,
第二行输入k个整数。
这只是其中一种结果
样例输出: 73=21 21*12=252 252-2=250 250/2=125
二:思路:
1.排列树 + 子集树
2.我们穷举所有的可能的数字组合,这是全排列,但要注意的是在全排列中,如果给出的数据有重复的数字,那么我们求的全排列后的数据是有重复的,所以我们要进行去重处理;
3.得到全排列的结果后,我们要对每一个全排列的结果进行子集树处理,因为每一次往下递归都是’+’,’-’,’*’,’/’;,递归的终止条件就是当我们统计 sum == M时候,或者是我们的操作符个数满足要求的时候,如果仅仅是操作符满足个数是不统计操作符的结果的;
二:上码
/*
1.题目:
给定k个正整数,用算术运算符+,-,*,/ 将这k个正整数连接起来,是最终的得数恰为m。
如果有多组满足要求的表达式,只要输出一组,每一步算式用分号隔开。
如果无法得到m,得输出“No Solution”。
样例输入:
5 125
7 2 2 12 3
第一行输入整数的个数k和m,
第二行输入k个整数。
样例输出: 7*3=21 21*12=252 252-2=250 250/2=1252.思路分析:
从输出的样例顺序(7,3,12,2,2)可以得知,这是一种全排列后的结果,对于每组数据之间的加减乘除,我们
可以做子集树划分 */#include<bits/stdc++.h>
using namespace std;int N,M;
int cnt = 0;
vector<vector<int> >ans1;
vector<int> path1;vector<vector<char> >ans2;
vector<char> path2;//求出数字的全排列组合
void backtacking1(int N,vector<int>& vec,vector<bool>& vis){if(path1.size() == N){ans1.push_back(path1);return;}for(int i = 0; i < N; i++){if(vis[i] == true) continue;vis[i] = true;path1.push_back(vec[i]);backtacking1(N,vec,vis);path1.pop_back();vis[i] = false;}
}//子集树的排列
//横向的for循环为加减乘除,纵向的为一种全排列的结果
void backtacking2(vector<char>& v1,vector<int>& v2,int sum,int index){if(sum == M || path2.size() == N - 1){ //这里递归结束的条件为满足 M时 if(sum == M){ //还有的是操作符号的个数不能大于 N - 1个 ans2.push_back(path2);cnt = 1;}return ; }for(int i = 0; i < 4; i++){//这里小于4是有4个操作符 char ch = v1[i];if(ch == '+'){sum = sum + v2[index];}else if(ch == '-'){sum = sum - v2[index];}else if(ch == '*'){sum = sum * v2[index];}else if(ch == '/'){sum = sum / v2[index];}index++;//表示纵向的一种全排列结果集的下标 path2.push_back(ch);//将符号存进去 backtacking2(v1,v2,sum,index);//这里的顺序不能乱 path2.pop_back();index--;if(ch == '+'){sum = sum - v2[index];}else if(ch == '-'){sum = sum + v2[index];}else if(ch == '*'){sum = sum / v2[index];}else if(ch == '/'){sum = sum * v2[index];} }
} //验证全排列
void text01(){ for(int i = 0; i < ans1.size(); i++){for(int j = 0; j < N; j++){cout << ans1[i][j] << " ";}cout << endl;}
}int main(){vector<int>v1;//输入的数据vector<vector<int> >v3;//记录可行解 vector<char> operators(4); set<int>s[100]; set<int>:: iterator st;cin >> N >> M;for(int i = 0; i < N; i++){int num;cin >> num;v1.push_back(num);}cout << endl; vector<bool> vis(N,false); backtacking1(N,v1,vis); operators[0] = '+';operators[1] = '-';operators[2] = '*';operators[3] = '/';for(int i = 0; i < ans1.size(); i++){vector<int> v2;int count = 0; for(int j = 0; j < N; j++){ v2.push_back(ans1[i][j]);if(ans1[i-1][j] == ans1[i][j] && i != 0){count++; } }if(count == N){ // 这是为了去重的,因为在全排列中,如果有重复的元素,那么最终输出 continue; //的结果是有重复的组数据的 }int num = v2[0];backtacking2(operators,v2,num,1);if(cnt == 1){//这里存的是满足条件的 数字组合 v3.push_back(v2);} cnt = 0;}for(int i = 0; i < ans2.size(); i++){//v3.size() 和ans2.size()大小是一致的 cout << "操作数为:";for(int j = 0; j < N; j++){cout << v3[i][j] << ' ';}cout << endl;cout << "操作符为:"; for(int j = 0; j < N - 1; j++){//N个数需要 N-1个操作符 cout << ans2[i][j] << ' ';}cout << endl;}} //5 125
//7 3 12 2 2//5 125
//7 2 2 12 3
下方的的数据按照操作符都可以得到正确结果