PKU/HDU Sum It Up

题目传送门:http://poj.org/problem?id=1564

      http://acm.hdu.edu.cn/showproblem.php?pid=1258

  解法:深搜+判重

  n<=12直接深搜也不会超时,而且数据较弱。题目意思说每个加法中的数字可以出现的次数不能多于原来list里面的数字。但是可能出现一样的加法式子。

比如样例中的4 6 4 3 2 2 1 1,如果直接深搜就会出现两个3+1和两个2+1+1,所以加一个判断重复就可以了。类似的搜索还可以采用状态压缩的解法,效率更快。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <map>
#include <cstring>
#include <string.h>
#include <fstream>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

int a[15], tot, n;
bool flag;

int get_sum(int j){
    int l = n, tot = 0;
    while (j > 0){
        if (j % 2)
            tot += a[l];
        j /= 2;
        l--;
    }
    return tot;
}
int d[1<<12], k;
void out_put(int x){
    int c[15], k = n;
    while (k >= 1){
        c[k--] = x % 2;
        x /= 2;
    }
    bool temp = false;
    for (int i = 1; i <= n; i++)
        if (c[i]){
            if (temp)printf("+");
            else temp = true;
            printf("%d", a[i]);
        }
    printf("\n");
    return;
}

bool is_same(int i, int j){
    vector<int> u, v;
    int l = n;
    while (i > 0){
        if (i % 2)
            u.push_back(a[l]);
        i /= 2;
        l--;
    }
    l = n;
    while (j > 0){
        if (j % 2)
            v.push_back(a[l]);
        j /= 2;
        l--;
    }
    if (u.size() != v.size())return false;
    for (l = 0; l < u.size(); l++)
        if (u[l] != v[l])return false;
    return true;
}

void dfs(int s, int i){
    if (i == n+1){
        s /= 2;
        if (get_sum(s) == tot){
            //判重
            int x = 0, j;
            for (j = 0; j < k; j++)
                if (is_same(s, d[j])){
                    x = 1;
                    break;
                }
            if (!x){
                flag = false;
                d[k++] = s;
            }
        }
        return;
    }
    int t = s * 2;
    dfs(t + 0, i + 1);
    dfs(t + 1, i + 1);
    return;
}

int main(){

    int i;

    while (scanf("%d%d", &tot, &n) != EOF)
    {
        if (!n)break;
        for (i = 1; i <= n; i++)
            scanf("%d", &a[i]);

        printf("Sums of %d:\n", tot);
        k = 0;
        flag = true;

        dfs(0, 0);
        for (i = k-1; i >= 0; i--)
            out_put(d[i]);
        if (flag)printf("NONE\n");
    }
    return 0;
}


 

 

 

 

posted @ 2011-08-24 10:47  like@neu  阅读(195)  评论(0编辑  收藏  举报