2018.3.10 模拟赛——(1)Closest

题目大意:

给出A与B,都是n位数(n<=60),需要找到最近的靠近A的n位数,使得它们的十进制表示是B中所有数字的某个排列。
假如A=3022并且B=1232,用B的数字我们可以获得以下的4位数字:1223, 1232, 1322, 2123, 2132, 2213, 2231, 2312, 2321, 3122, 3212和3221。最小的比A大或者和A相等的数,且用B中的数字组成的是3122,并且最大的严格比A小的数是2321。

解题思路:

快排+纯模拟
然后先判断最小的是否大于或等于A,如果大于或等于A则没有小于A的,直接输出最小的和0就好
还有判断最大的是否小于A,如果小于A则没有大于或等于A的,直接输出0和最大的就好
若上面两个都不成立,则都存在,现在开始用一组数据解释我的思路
数据:
3000203
4562454
用一个桶统计每个数字在B中出现的次数
0 1 2 3 4 5 6 7 8 9
0 0 1 0 3 2 1 0 0 0
判断(上面讲了的两个判断),
发现两种都存在,就开始找,先输出最小的大于或等于A的,就找最大的
a[1]是3,找比它大的在B中存在的最小的,找到是4,就用4当b[1],交换当前的b[1],b[2]也是,若b[i]>a[i],则后面的可以不找,因为b[i]>a[i]后面无论怎么排都不会使A>B,所以直接sort后面的,从小到大排序就可以了
然后找小于A的最大的a[1]是3,找比它小的最大的,自然就是2,然后发现b[i]

源程序:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char cs[101];
int a[101],b[101],c[101],s[11],n;
bool cmp(int x,int y) 
//快排判断,从小到大排(完全可以省略)
{
    return x<y;
}
bool cmp1(int x,int y)//快盘判断,从大到小排
{
    return x>y;
}
int main()
{
    //freopen("closest.in","r",stdin);
    //freopen("closest.out","w",stdout);
    cin>>cs;
    n=strlen(cs);
    for (int i=0;i<n;i++)
     a[i+1]=cs[i]-48;
    cin>>cs;
    for (int i=0;i<n;i++)
     b[i+1]=cs[i]-48;//读入处理不多说
    sort(b+1,b+n+1,cmp);//从这里开始
    int f=0;
    int k=1;
    while (!b[k]) k++;
    int l=1;
    int y=n;
    swap(b[k],b[1]);
    int x=0;
    for (int i=1;i<=n;i++)
     if (b[i]==a[i]) x++;
     else if(b[i]>a[i]) {x=n;break;}
     else if (b[i]<a[i]) {x=0;break;}
    if (x==n)
     f=-1,swap(b[k],b[1]);
    else if (b[l]<a[1]) f=1;
    else if (b[1]==a[1]) while (b[l]==a[l]&&l<n)
                          {
                            l++;
                            if (b[l]>a[l])
                             {f=0;break;} else f=1;
                          }
    else f=0;
    if (f==0)
    {
        for (int i=1;i<=n;i++) 
         printf("%d",b[i]);
        printf("\n0");
        return 0;
    }
    else if (f==-1)
         {
            printf("%d",b[k]);
            for (int i=1;i<=n;i++)
             if (i!=k)
             printf("%d",b[i]);
            printf("\n0");
            return 0;
         }
    sort(b+1,b+n+1,cmp1);
    f=0;
    k=1;
    l=k;
    if (b[l]>a[1]) f=1;
    else if (b[1]==a[1]) while (b[l]==a[l]&&l<n)
                          {
                            l++;
                            if (b[l]<=a[l])
                             {f=0;break;} else f=1;
                          }
    else f=0;
    if (f==0)
    {
        printf("0\n");
        for (int i=1;i<=n;i++) 
         printf("%d",b[i]);
        return 0;
    }//到这里都是上面所说的两种判断
    sort(b+1,b+n+1,cmp);//找大于或等于A的最小的
    for (int i=0;i<=10;i++)
     for (int j=1;j<=n;j++)
      if (b[j]==i)
       s[i]++;     //存入桶
    l=1;
    k=a[l];
    while (!s[k]&&k<10)
        k++;
    sort(b+1,b+n+1,cmp1);
    int p=1;
    while (b[p]!=k)
     p++;
    swap(b[1],b[p]);//交换
    x=0;
    for (int i=1;i<=n;i++)
     if (b[i]==a[i]) x++;
     else if(b[i]>a[i]) {x=n;break;}
     else if (b[i]<a[i]) {x=0;break;}
    if (x!=n)
     k++;
    x=0;
    p=1;
    while (b[p]!=k)
     p++;
    swap(b[1],b[p]);
    s[k]--;
    p=1;
    bool hh=0;
    if (a[l]<k)
     sort(b+2,b+n+1,cmp);
     //如果第一位就大于A的第一位,后面无论如何都可以,所以直接快排
    else
    {
        hh=0;
        sort(b+l+1,b+n+1,cmp1);
        //否则,先快排一次后面的,然后一次一次纠正
        while (l<n)
         {
            l++;
            p=l;
            k=a[l];
            while (!s[k]&&k<10)
             k++;
            if (k==10)‘
            //这里就是已经找不到了,但是前面判断过一定有,
            //由此得知,前面有错
            //所以这里纠正一下
            {
                hh=0;
                for (int o=l-1;o>=1;o--)
                 if (hh) break;
                 else
                 for (int h=1;h<=l;h++)
                  if (o!=h&&b[h]>b[o])
                   {swap(b[h],b[o]);hh=1;
                    sort(b+o+1,b+n+1,cmp);
                    //纠正了之后必定大于,直接排序
                    break;
                   }
            }
            while (b[p]!=k&&p<n)
            p++;
            if (a[l]<=b[p])
            {
             swap(b[l],b[p]);
             if(a[l]<b[p]&&!s[a[l]])
             {
              sort(b+l+1,b+n+1,cmp);
              break;
             }
             s[k]--;
             //这些操作解题思路就有讲过,这里就不讲了
            } 
            p=l;
            if (hh)
             break;
            //如果已经纠正过了,就找到了正解,退出就好了
         }
    }
    for (int i=1;i<=n;i++)
     printf("%d",b[i]),c[i]=b[i];//输出
    sort(c+1,c+n+1,cmp1);
    //从大到小排序(我也不知道为什么)
    for (int i=0;i<=10;i++)
    s[i]=0;
    for (int i=0;i<=10;i++)
     for (int j=1;j<=n;j++)
      if (c[j]==i)
       s[i]++;
    l=1;
    k=a[l];
    while (!s[k]&&k>1)
        k--;
    sort(c+1,c+n+1,cmp);
    p=1;
    while (c[p]!=k&&p<n)
     p++;
    swap(c[1],c[p]);
    for (int i=1;i<=n;i++)
     if (c[i]==a[i]) x++;
     else if(c[i]<a[i]) {x=0;break;}
     else if (c[i]>a[i]) {x=n;break;}
    if (x==n)
     k--;
    x=0;
    p=1;
    while (c[p]!=k)
     p++;
    swap(c[1],c[p]);
    s[k]--;
    p=1;
    if (a[l]>k)
     sort(c+2,c+n+1,cmp1);
     else
    {
        hh=0;
        sort(c+l+1,c+n+1,cmp);
        while (l<n)
         {

            l++;
            p=l;
            k=a[l];
            while (!s[k]&&k>-1)
             k--;
            if (k==-1)
            {
                hh=0;
                for (int o=l-1;o>=1;o--)
                 if (hh) break;
                 else
                 for (int h=1;h<=l;h++)
                  if (o!=h&&c[h]<c[o])
                   {swap(c[h],c[o]);hh=1;
                    sort(c+o+1,c+n+1,cmp1);
                    break;
                   }
            }
            while (c[p]!=k&&p<n)
            p++;
            if (a[l]>=c[p])
            {
             swap(c[l],c[p]);
             if (a[l]>c[p]&&!s[a[l]])
             {  
              sort(c+l+1,c+n+1,cmp1);
              break;
             }
             s[k]--;
            }
            p=l;
         }
    }//这里则是相反
    for (int i=1;i<=n;i++)
     if (c[i]==a[i]) x++;
    //这里要纠正,因为上面我是等于也要那啥
    if (x==n)
      {
        l=n;
        int q=c[n];
        while (c[n]==c[l])
         l--;
        swap(c[n],c[l]); 
      }//然后如果完全相等纠正一波
    puts("");
    for (int i=1;i<=n;i++)
     printf("%d",c[i]);//愉快输出
}

End.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值