day_5-acm 好题思考好方法

本文针对HDU5676问题提供两种解决思路:一是通过深度优先搜索生成所有可能的幸运数字并利用二分查找定位;二是采用全排列结合字符串比较的方式寻找最小子集。最终给出具体实现代码。

hdu 5676 ztr loves lucky numbers

这道题想了很久,但总是超时,所以搜索了题解,认真的思考了一番。
点我看原题

Problem Description

ztr loves lucky numbers. Everybody knows that positive integers are lucky if their decimal representation doesn’t contain digits other than 4 and 7. For example, numbers 47, 744, 4 are lucky and 5, 17, 467 are not.

Lucky number is super lucky if it’s decimal representation contains equal amount of digits 4 and 7. For example, numbers 47, 7744, 474477 are super lucky and 4, 744, 467 are not.

One day ztr came across a positive integer n. Help him to find the least super lucky number which is not less than n.

Input

There are T(1≤n≤105) cases

For each cases:

The only line contains a positive integer n(1≤n≤1018). This number doesn’t have leading zeroes.

Output

For each cases
Output the answer

Sample Input

2
4500
47

Sample Output

4747
47

方法一:打表+二分查找

因为18位数据以内的lucky numbers 是有限的,所以我们将他们全部找出来,打出数据的列表,然后再二分查找

代码

/*dfs深度搜索法,先打表再二分查找。*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>

#define INF 0x3f3f3f3f
#define N 100010
using namespace std;

long long a[N];
int cnt;
void dfs(int l,int r,int len,long long num)
{
    if(l>len/2||r>len/2) //一次排列完成,结束递归
        return ;
    if(l+r==len&&l==r)  //将数据sum复制到数组中去,结束位数排列
    {
        a[cnt++]=num;
        return ;
    }
    if(l<=len/2)
        dfs(l+1,r,len,num*10+4);
    if(r<=len/2)
        dfs(l,r+1,len,num*10+7);

}
int main()
{
    cnt=0;
    for(int i=2;i<=18;i+=2)
        dfs(0,0,i,0);
    int t;
    long long n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        if(n>777777777444444444ll)   //特判,数据超出long long ;
            printf("44444444447777777777\n");
        else
            printf("%lld\n",a[lower_bound(a,a+cnt,n)-a]);
    }
    return 0;
}

总结一

函数lower_bound用来查找数组中第一个不小于需要查找的数据,注意返回的是数据的地址:http://blog.youkuaiyun.com/niushuai666/article/details/6734403

方法二:全排列查找

这里使用next_permutation函数来将所需要相应位数的4和7进行全排列,然后用strcmp函数找出所需要的数据输出。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
char b[50],c[50];
int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%s", b);
        int len = strlen(b);
        if (len & 1)//奇数位时
        {
            for (int i = 0; i <= len / 2; i++)printf("4");
            for (int i = 0; i <= len / 2; i++)printf("7");
            printf("\n"); continue;
        }
        for (int i = 0; i < len / 2; i++)c[i]='4';
        for (int i = len/2; i < len; i++)c[i]='7';
        c[len] = 0;     //4447770
        int f = 0;
        do
        {
            if (strcmp(b, c) <= 0)//b<=c
            {
                printf("%s\n", c);
                f = 1; break;
            }
        } while (next_permutation(c, c + len));     //将数据按照从小到大一次进行全排列
        if (f==0)   //18位数据超范围时 (b>777777777444444444);
        {
            for (int i = 0; i <= len / 2; i++)printf("4");
            for (int i = 0; i <= len / 2; i++)printf("7");
            printf("\n");
        }
    }
    return 0;
}

总结二

next_permutation 函数的使用方法:http://blog.sina.com.cn/s/blog_9f7ea4390101101u.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值