// 1612K 16MS G++
#include <cstdio>
#include <queue>
#include <cstring>
#include <string>
#include <cstdlib>
using namespace std;
int targetNum;
int inputNum;
string inputNumStr;
struct BFSNode {
int splitterPos; // x means insert splitter in xth pos
int splitterNum;
int sum;
};
typedef struct BFSNode BFSNode;
queue<BFSNode> BFSQueue;
char BFSFlag[1024*1024];
int MAXappearTime;
int MAXSplitPos;
#define INF 999999
int bitArray[32];
void initBitArray() {
int val = 1;
for (int i = 1; i <= 30; i++) {
bitArray[i] = val;
val <<= 1;
// printf("%d\n", val);
}
}
int MAX;
int BFS() {
MAX = -INF;
while(BFSQueue.size()) {
BFSQueue.pop();
}
memset(BFSFlag, 0, sizeof(BFSFlag));
int inputLength = inputNumStr.length();
BFSNode beginNode;
// memset(beginNode.splitterPos, 0, sizeof(beginNode.splitterPos));
beginNode.splitterPos = 0;
beginNode.splitterNum = 0;
beginNode.sum = inputNum;
BFSFlag[0] = 1;
if (inputNum <= targetNum) {
if (inputNum > MAX) {
MAX = inputNum;
MAXappearTime = 1;
MAXSplitPos= 0;
}
}
BFSQueue.push(beginNode);
while(BFSQueue.size()) {
BFSNode curNode = BFSQueue.front();
BFSQueue.pop();
int curSum = curNode.sum;
// printf("%d\n", curSum);
int curSpltterNum = curNode.splitterNum;
for (int i = 1; i <= inputLength - 1; i++) {
// printf("%d %d\n", i, bitArray[i]);
if (!(curNode.splitterPos & bitArray[i])) { // if pos i not be insert split yet
int newSplitPos = (curNode.splitterPos | bitArray[i]); // insert split in ith pos
if (!BFSFlag[newSplitPos]) { // if this split combination is not processed yet
BFSFlag[newSplitPos] = 1;
int beforePos = 0;
int afterPos = inputLength - 1;
for (int j = i-1; j > 0; j--) {
// printf("A %d %d\n", curNode.splitterPos, bitArray[j]);
if (curNode.splitterPos & bitArray[j]) {
beforePos = j;
break;
}
}
for (int j = i+1; j <= inputLength - 1; j++) {
if (curNode.splitterPos & bitArray[j]) {
afterPos = j;
break;
}
}
string strOrignalNumStr = inputNumStr.substr(beforePos, afterPos - beforePos + 1);
string split1Str = inputNumStr.substr(beforePos, i - beforePos);
string split2Str = inputNumStr.substr(i, afterPos - i + 1);
// printf("%d %d %d %s %s %s\n", beforePos, i, curSum, strOrignalNumStr.c_str(), split1Str.c_str(), split2Str.c_str());
int originalNum = atoi(strOrignalNumStr.c_str());
int split1 = atoi(split1Str.c_str());
int split2 = atoi(split2Str.c_str());
int newSum = curSum - originalNum + split1 + split2;
if (newSum <= targetNum) {
if (newSum == MAX) {
MAXappearTime++;
} else if (newSum > MAX) {
MAX = newSum;
MAXappearTime = 1;
MAXSplitPos = newSplitPos;
}
}
BFSNode newNode;
newNode.splitterPos = newSplitPos;
newNode.splitterNum = curSpltterNum + 1;
newNode.sum = newSum;
BFSQueue.push(newNode);
}
}
}
}
}
void solve() {
BFS();
if (MAX == -INF) {
printf("error\n");
} else if (MAXappearTime > 1) {
printf("rejected\n");
} else {
printf("%d ", MAX);
for (int i = 0; i < inputNumStr.length(); i++) {
if (i > 0 && (MAXSplitPos & bitArray[i])) {
printf(" ");
}
printf("%c", inputNumStr[i]);
}
printf("\n");
}
}
int main() {
initBitArray();
char tmp[30];
while(1) {
scanf("%d %d", &targetNum, &inputNum);
if (targetNum == 0 && inputNum == 0) {
return 0;
}
if (inputNum == targetNum) {
printf("%d %d\n", inputNum, targetNum);
continue;
}
sprintf(tmp ,"%d", inputNum);
// itoa(inputNum, tmp, 10);
inputNumStr = tmp;
solve();
}
}
这种分裂式问题一般都可以用BFS解,不过就是在表述方式上要下些功夫,
因为是将一个数字不断的拆分,直到最后每个piece都只有一位,所以,如果表示这种拆分要好好考虑,关系到以后实现的难度。
最初是想在BFSNode中搞一个int数组,数组保存的就是当前被拆分的数字,并且还有一个变量来记录被拆分成了多少个piece,
后来发现,这么表示,想对当前的数字进行再拆分的话会比较困难,要遍历当前数组,拆分完了还要为新分出来的数字腾位置,最关键的是,
BFSFLAG这种情况下没办法实现(将int数组 硬搞 成hash值也行),因此不得不另外还一种思路。
突然想到,可以这样表示拆分的情况,将一个数字S顺序拆分为几个数字,其实就是在S中插入了几个splitter罢了(1234 -> 1 23 4等价与 在2和4插入了两个splitter-> 1 splitter 23 spliter 4),这样,搞一个数组,保存S的某个位置是否插入了spliter,就可以表示拆分的情况了,而为了能实现BFSFlag, 以及节省空间,可以用一个int作为bitmap来保存spliter的插入情况,第i位是1表示在第i位插入了spliter。
这样在BFS的时候,拿到本次BFSNode的spliterMap, 从1(第0个位置插入spliter不会改变数值,因此不考虑)开始察看是否有位置可以插入新的spliter,如果有,就用新的splliterMap检查BFSFlag,如果这种spliter插入方案没有尝试过,就求出此方案下的sum, 求sum也简单,首先有了没插入新spliter前的Bsum,在位置i插入新spliter以后,从i-
1开始向前搜索第一个spliter B, 从i+1向后搜索第一个spliter E, 然后本次新的spliter其实就是拆分了 B到E-1这段数字,那么Bsum减去此段数字的值,再加上拆分以后的两段数字的值(B<->i-1, i<->E-1)就是此spliter插入以后的sum值,同时维护一个全局的MAX 和 MAXappearTime 以及MAXsplitMap, 分别保存了目前得到的最大sum,已经最大sum出现的次数(可能不同的拆分会有相同的sum),以及此MAX都应的拆分方案,每次插入一个新的spliter,就检查是否需要更新上面3个变量,
最后,如果MAX还是初始值,说明没有能满足需求的,error,如果有但是MAXappearTime>1, reject, 否则就输出MAX ,然后按照spliterMap输出数字的拆分情况。
这道题难其实就在于合适的表达拆分方式,剩下的就是纯考验耐性了.