思路:搜索
分析:
1 给定一个等式判断两边是否相等,如果一个等式相等那么通过移项到同一边可以得到正数的和等于负数
2 那么通过分析1我们可以知道我们可以求出这个等式的所有数字的和,判断和是否为偶数。如果和为奇数那么肯定不可能成立,因为不能被平分
3 通过分析2的剪枝之后,那么可以知道题目说了最多有16 个数字。那么我们就搜索这个2^16种状态,找到一个满足的即可。注意在搜索的过程中可以进行剪枝
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 10000;
char inStr[MAXN];
char expStr[MAXN];
int num[MAXN];
int pos , cnt , sum;
void init(char *str){
int len = strlen(str);
bool isLeft = true;
pos = sum = 0;
cnt = 1;
int i = 0;
while(i < len){
if(isalnum(str[i])){
int j = i;
int tmp = 0;
while(j < len && isalnum(str[j])){
tmp = tmp*10+str[j]-'0';
j++;
}
sum += tmp;
num[pos++] = tmp;
i = j-1;
}
else{
if(str[i] != ' ')
expStr[pos] = str[i];
if(str[i] == '+' && isLeft)
cnt++;
if(str[i] == '=')
isLeft = false;
if(str[i] == '-' && !isLeft)
cnt++;
}
i++;
}
}
void output(int *arr , int tmpPos){
bool vis[MAXN];
bool isLeft = true;
memset(vis , false , sizeof(vis));
for(int i = 0 ; i <= tmpPos ; i++)
vis[arr[i]] = true;
int tmpArr[MAXN];
int tmpArrPos = 0;
for(int i = 0 ; i < pos ; i++)
if(!vis[i])
tmpArr[tmpArrPos++] = i;
tmpArrPos--;
printf("%d" , num[arr[tmpPos--]]);
for(int i = 1 ; i < pos ; i++){
if(expStr[i] == '+'){
if(isLeft)
printf(" + %d" , num[arr[tmpPos--]]);
else
printf(" + %d" , num[tmpArr[tmpArrPos--]]);
}
else if(expStr[i] == '-'){
if(!isLeft)
printf(" - %d" , num[arr[tmpPos--]]);
else
printf(" - %d" , num[tmpArr[tmpArrPos--]]);
}
else{
isLeft = false;
printf(" = %d" , num[tmpArr[tmpArrPos--]]);
}
}
printf("\n");
}
void solve(){
int tmpNum = (1<<pos)-1;
int arr[MAXN];
sum >>= 1;
while(tmpNum){
int tmp = tmpNum;
int tmpCnt = -1;
int tmpPos = pos-1;
int tmpSum = 0;
while(tmp){
if(tmp&1){
tmpCnt++;
arr[tmpCnt] = tmpPos;
tmpSum += num[tmpPos];
}
tmpPos--;
tmp >>= 1;
if(tmpSum > sum || tmpCnt+1 > cnt)
break;
}
if(tmpCnt+1 == cnt && tmpSum == sum){
output(arr , tmpCnt);
return;
}
tmpNum--;
}
printf("no solution\n");
}
int main(){
while(gets(inStr)){
init(inStr);
if(sum&1)//如果是奇数
printf("no solution\n");
else
solve();
}
return 0;
}