hdu 1258 Sum It Up (dfs)

题意:

给出t(总和)和n,接下来给出n个数,用加号连接输出n个数字中所有满足和为t的式子。

且输出的式子中数字按降序排列,式子的先后按照字典序的方式比较,大的先输出(即先

比较第一个数的大小,如果相同则比较第二个数的大小,依次类推。。。)


算法:

1、由于式子中数字要按降序排列,故先把n个数按降序排列,这样也能保证式子之间输出

      的先后关系。

2、由于最多只有12个数,dfs把每个数取与不取暴利一遍。

3、避免输出重复,用mark二维数组把之前的组合都记录,输出之前check一下是否重复。


<br/>

开始走入思维误区,觉得重复的一定会是相邻的数字,因为排了序,所以一定是相邻的状态,

所以只用了一维的mark数组,每次mark记录的是前一个满足和为t的组合,输出前只判断当前

和之前是否相同,相同则重复不输出。


其实也确实是相邻的数字(排序后)可能造成重复,但不是在递归搜索过程中只有相邻的两个

状态可能造成重复。

如果相邻且相等的数字在前面,则中间搜索状态将它们隔开,它们就不是相邻状态,用一维

MARK数组判重就行不通了。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<vector>

using namespace std;

int a[20],t,n,flag,c;
bool vis[20];
int cnt[110];
vector<int> mark[1000];

bool cmp(int x,int y)
{
    return x>y;
}

void out()
{
    int f = 0;
    for(int i=0;i<n;i++)
    {
        if(vis[i])
        {
            if(!f)
            {
                printf("%d",a[i]);
                f = 1;
            }
            else printf("+%d",a[i]);
        }
    }
    printf("\n");
}

bool check()
{
    int num = 0;
    for(int i=0;i<c;i++)
    {
        int s = 0;
        for(int j=0;j<n;j++)
        {
            if(cnt[a[j]]!=mark[i][a[j]])
            {
                s = 1;
                continue;
            }
        }
        if(s) num++;
    }
    if(num == c) return true;
    else return false;
}

void dfs(int id,int sum)
{
    if(id>n || sum>t)
        return;
    if(sum == t && check())
    {
        flag = 1;
        out();
        for(int i=0;i<100;i++)
            mark[c].push_back(cnt[i]);
        c++;
        return ;
    }
    int x = a[id];
    vis[id] = true;
    cnt[x]++;
    dfs(id+1,sum+x);
    vis[id] = false;
    cnt[x]--;
    dfs(id+1,sum);
}

int main()
{
    while(scanf("%d%d",&t,&n)!=EOF)
    {
        if(t==0 && n==0)
            break;
        printf("Sums of %d:\n",t);
        flag = 0;
        c = 0;
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        sort(a,a+n,cmp);
        int i;
        memset(vis,0,sizeof(vis));
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<110;i++)
            mark[i].clear();
        for(i=0;a[i]>t && i<n;i++);
        if(i==n)
        {
            printf("NONE\n");
            continue;
        }
        dfs(i,0);
        if(!flag)
            printf("NONE\n");
    }
    return 0;
}

/*

434 12 94 94 93 74 66 60 49 38 35 34 27 2

Sums of 434:
94+94+93+66+60+27
94+94+93+66+49+38
94+94+74+60+49+34+27+2
94+94+66+60+49+35+34+2
94+93+74+66+38+35+34
94+93+74+60+49+35+27+2
94+93+66+60+49+38+34

*/



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值