深搜-某团笔试 选红包问题

题目: 圆桌上放了一圈红包形成环形,每个红包金额不同,围绕圆桌走一圈选择若干红包,规则是不能拿相邻的红包,请问拿到红包最多的总金额是多少?
输入: 红包个数N N行数组表示N个红包
输出: 最多的总金额
样例输入:
2
1,2
1,3,4
样例输出:
2
4

这道题有两个坎。

  1. 要将输入的数据给找出来。解决办法是,把输入的全部当场字符串存储,再在里面根据逗号,进行数据提取,最后存到数组里。
  2. 接下来就是选红包。第一反应就是深度优先搜索暴力破解。所谓的不能选相邻的红包,也就是一个剪枝的问题。若选择拿当前红包,那么拿下一个红包至少得隔一个;如果不选择当前红包,那么下一个红包就可以直接拿相邻的。

具体的见如下代码:

#include<stdio.h>
#include<string.h>

int maxValue; 
int len=0;  //用来存数据的个数 

int countNum(char* a,int start,int end) //此函数将数字字符串段转为数字 
{
    int result=0;
    int i=0,m=0;
    int j=start-end;
    int pownum;
    for(i=0;i<=(end-start);i++)
    {
        pownum=1;
        for(m=0;m<i;m++)
            pownum*=10;
        result+=(a[end-i]-'0') * pownum;
        j--;
    }
    return result;
}
int coverTonum(char* a,int* num)  //此函数从字符串中提取逗号之间的所有数字
{
    int i=0,k=0;
    int tempi=-1; //存储找到一个逗号时的索引值
    while(*(a+i)!='\0')
    {
        if(*(a+i)==',')
        {
            num[k]=countNum(a,tempi+1,i-1);
            tempi=i;
            k++;
        }
        i++;    
    }   
    num[k]=countNum(a,tempi+1,i-1);  //最后一个逗号右边应该还有一个数 
    return k+1;
}

void DFS(int* num,int* vis,int n,int value) //vis数组主要用来标记哪些红包被选中
{
    int i;
    if(value>maxValue)
        maxValue=value;
    if(n>len)
        return ;
    else
    {
        vis[n]=1;
        if(vis[0]==1 && vis[len-1]==1) //剪枝,同时选中的情况不考虑 
            return ;
        DFS(num,vis,n+2,value+num[n]);
        vis[n]=0;
        DFS(num,vis,n+1,value); 
    }
}

int main()
{
    int N,i;
    scanf("%d",&N);
    while(N--)
    {
        char a[100];
        int num[100];
        int vis[100];
        memset(num,0,sizeof(num));
        memset(vis,0,sizeof(vis));
        scanf("%s",a);
        len=coverTonum(a,num);
        DFS(num,vis,0,0);
        printf("maxValue : %d\n",maxValue);
    }
}

除了以上方式,还有两种思路:

  1. 首尾红包不能同时拿,那么最大值就是 num[0]~num[n-2] 与 num[1]~num[n-1] 两者之间取红包的最大值,仍然可用深搜破解。
  2. 用动态规划思想。如果取第j个红包,获得的价值最大,记为Func(j),那么红包最大价值Func(j)就可以分解为隔它一个或者隔它两个红包处取得的最优解加上num[j]的价值。用公式表示就是:Func(j)=Max{ Func(j-2),Func(j-3) }+num[j] 。具体代码,待以后实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值