贪心

这次花了三个小时写一个题,期间真的wa到哭,难倒是不难,就是很麻烦,上题

描述

给定一些不同的一位数字,你可以从这些数字中选择若干个,并将它们按一定顺序排列,组成一个整数,把剩下的数字按一定顺序排列,组成另一个整数。组成的整数不能以0开头(除非这个整数只有1位)。

例如,给定6个数字,0,1,2,4,6,7,你可以用它们组成一对数10和2467,当然,还可以组成其他的很多对数,比如210和764,204和176。这些对数中两个数差的绝对值最小的是204和176,为28。

给定N个不同的0~9之间的数字,请你求出用这些数字组成的每对数中,差的绝对值最小的一对(或多对)数的绝对值是多少?

格式

输入格式

第一行包括一个数T(T≤1000),为测试数据的组数。

每组数据包括两行,第一行为一个数N(2≤N≤10),表示数字的个数。下面一行为N个不同的一位数字。

输出格式

T行,每行一个数,表示第i个数据的答案。即最小的差的绝对值。

样例1

样例输入1

2
6
0 1 2 4 6 7
4
1 6 3 4

样例输出1

28
5

提示

友情提示:每个数字出现了偶数次会抵消。

例如2 2 2当作一个2来处理,3 3相当于没有数字。

这个在题目中好象没有说。

来源

某校NOIP模拟题


思路:就是分N=2和N>2(要分奇偶)

输入时要注意把重复的去掉
贪心策略:1、如果是N=2,那么就这两个数相减。

2、如果N>2为偶,选两个不为零的数之差最小分别作为所求两个数的首位,如果出现最小的有多个,全部求出结果之后再求最小值。然后把那两个选出的数都置为-1,这两个选出的数大的要求剩下的位尽可能小,小的剩下的位尽可能大,相减才会更小。

3、如果N>2为奇,选一个不为零的最小的数作为较大的那个数的首位,选最大的数作为较小的那个数的首位,剩下的与2中类似。

AC代码:
#include<bits/stdc++.h>
using namespace std;
bool cmp(int a,int b)
{
    return a>b;
}
int Pow(int n)
{
    int ans=1;
    for(int i=1;i<=n;i++)
        ans*=10;
    return ans;
}
int main()
{
    int T,N,n;
    int a[15];
    int b[100];
    int book[100];
    int vis[100];
    int c[15];
    cin>>T;
    while(T--)
    {
        N=0;
        memset(a,0,sizeof a);
        memset(book,0,sizeof book);
        memset(vis,0,sizeof vis);
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>b[i];
            if(!book[b[i]])
            {
                a[++N]=b[i];
                book[b[i]]=1;
            }
        }
        int ans,_min=999999;
        sort(a+1,a+N+1);
        int u,v;
        if(N==2)
        {
            ans=abs(a[1]-a[2]);
            _min=ans;
        }
        else if(N%2==0)
        {
            int M=10;
            int Min=9999999;
            memcpy(c,a,sizeof a);
            while(M--)
            {
            for(int i=1;i<=N;i++)
            {
                int flag=0;
                for(int j=i+1;j<=N;j++)
                   if(abs(a[i]-a[j])<=Min&&a[i]&&a[j])
                   {
                      Min=abs(a[i]-a[j]);
                      u=i;
                      v=j;
                     if(!vis[u])
                     {
                         vis[u]=1;
                         flag=1;
                         break;
                     }
                   }//u<v,a[u]<a[v]
                if(flag)
                    break;
            }
            int prod=a[v];
            int prox=a[u];
            a[u]=-1;
            a[v]=-1;
            sort(a+1,a+N+1);
            prod*=Pow(N/2-1);
            for(int i=3,k=N/2-2;i<=(N-2)/2+2;i++,k--)
                prod+=a[i]*Pow(k);
            sort(a+1,a+N+1,cmp);
            prox*=Pow(N/2-1);
            for(int i=1,k=N/2-2;i<=(N-2)/2;i++,k--)
                prox+=a[i]*Pow(k);
            ans=prod-prox;
            _min=min(ans,_min);
            memcpy(a,c,sizeof c);
            }
        }
        else
        {
            int prod;
            for(int i=1;i<=N;i++)
                if(a[i])
            {
                prod=a[u=i];
                break;
            }
            int prox=a[N];
            a[u]=-1;
            a[N]=-1;
            sort(a+1,a+N+1);
            prod*=Pow((N-1)/2);
            for(int i=3,k=(N-1)/2-1;i<=(N-1)/2+2;i++,k--)
                prod+=a[i]*Pow(k);
            sort(a+1,a+N+1,cmp);
            prox*=Pow((N-1)/2-1);
            for(int i=1,k=(N-1)/2-2;i<=(N-1)/2-1;i++,k--)
                prox+=a[i]*Pow(k);
            ans=prod-prox;
            _min=ans;
        }
        cout<<_min<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值