poj-1416

31 篇文章 0 订阅
// 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输出数字的拆分情况。

这道题难其实就在于合适的表达拆分方式,剩下的就是纯考验耐性了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值