pku 1011(dfs)

dfs题目  有点麻烦啊   先写了一次wrong answer了

参考了一下discuss

错在了这种类型的数据上

10

21 14 13 11 9 6 4 3 2 1

正确的匹配应该是:
21
14 4 3
13 6 2
11 9 1
分析了一下应该是  在确定长度为21 是否满足条件时我是这么搜的
21
14 6 1
13 4 3 这里无法满足条件后就直接判断长度21 不行了
然后重新写过剪枝不够高明  TLE一次
参考了下discuss里别人的代码总算是改好了  32MS  AC
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

int num[80];
int sum;
int n;
bool pan[80];
int len;

int main(int argc, char *argv[]) {
    bool dfs(int sum, int rest, int i, int w);
    while (cin >> n && n) {
        int i(0);
        sum = 0;
        while (i < n) {
            cin >> num[i];
            sum += num[i];
            ++i;
        }

        sort(num, num + n, greater<int>());   //进行降序排列

     len = num[0];
      
        while (1) {
            if (sum % len) {   //满足条件的长度必然是总长度的约数
                ++len;
                continue;
            }
            memset(pan, 0, sizeof (pan));
            // cout << "len=" << len << endl;

            if (dfs(sum, len, 0, 0)) {
                cout << len << endl;

                break;
            }
            ++len;
        }

    }

    return EXIT_SUCCESS;
}

bool dfs(int total, int rest, int i, int w) {

    int wrong=0;         //这里是针对重复数据的,比如判断某数不符合条件后,若后面一个数与它一样,则不用继续搜索判断了
    if (total == 0) return true;
    if (rest == 0) {

       return dfs(total - len, len, i + 1, 0);

    }

    int j(w);
    while (j < n) {
        if (!pan[j]) {
            if (pan[j] <= rest) {
                if(num[j]==wrong) {++j;continue;}
                pan[j] = 1;
                if (dfs(total, rest - num[j], i, j + 1) ) return true;
                wrong=num[j];
                pan[j] = 0;
            } 
            if(w==0) break;   //这个剪枝非常巧妙,很难想到
        }

        ++j;
    }
    return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值