Hard-13 编码问题

鸽了很多天,忙了一堆乱七八糟的事情,现在静下心来,重新做一下这题——背景(咕咕)

题目贴在这里:

 设有一个整形数组 A[0..N-1];存放的元素为 0~N-1 (1<N<=10)之间的整数,且 A[i]≠A[j](i≠j)。例如,当N=6时,有:A=(4,3,0,5,1,2)。此时,数组A的编码定义如下:
    A[0]编码为0;
    A[i]编码为:在A[0],A[1],…,A[i-1]中比A[i]的值小的个数 (i=1,2,…,N-1)
    例如上面数组 A的编码为:B=(0,0,0,3,1,2)
若给出数组A,则可求出其编码。同理,若给出数组A的编码,可求出A中的原数据。

输入:
    推导方向(取值为1或2,如为1,则表示根据数组求数组编码;如为2,则表示根据编码反求数组)
    数组个数
    数组或数组编码元素

输出:
    数组编码、或数组本身(元素之间以空格分隔)

        正向推当前位前面比当前位小的数字的个数这个很简单,两层for循环就搞定了,就不展开了,这里重点分析第二个小问题,逆推数字的排序。

主要思路及算法:

        从最大数的特殊性可以得到一种做法,那就是从当前的最大的数开始插入,未插入的位置给一个值,作为统计的对象,也就是比当前位小的数;对于已经插入的位置,则将该处的计数值改成不计数的值,表示这个位置的数更大,这也就利用了第一问的计数规则。

        更加具体的解释:

        以题目给出的一个例子为例,第一行是创建的计数用的数组,第二行是给出的条件,第三行是填格子,算结果。

        5是最大的,找到对应的格子就可以放入这个数字,4同理。由此,第一行的对应位置更改状态。当填入3的时候,两个-1不计数,由此填到最后一位。

        这就是大致的思路。

 来到代码实现:

        其实大致思路清晰之后,需要做的也是两个for循环寻找插入点而已,如下:

        这里重点分析一下为什么是要设置n和k,这第二个for如何运行的:

        首先从最后一个点开始找,由于大数的特殊性,前面可以计数的位置都可以计入总数,也就是当前位置的数(条件中),一定要等于前面有的可计数的数的个数,由此向前循环判断即可。

如果计数点到了第一个数,那就不必判断了,舍弃这个大数,让它在第一位喝西北风就行了。

            int a,b;
            scanf("%d%d",&a,&b);
            int y[10];    // 填计数参量 
            int d[10]={0}; // 插入对应元素,也就是原有的数字排序
            int i,j,k,m,n=0;
            for(j=b-1;j>0;j--)   // 从最大数开始找插入点 
			{
				for(k=b-1;k>=0;k--)  // 寻找匹配的插入点,也就是计数
				{
					n=0;
					for(m=0;m<k;m++) 
   					{
						if(y[m]>=0)   // 对非负一位计数 
						n++;
					}
					if(y[k]==n)
					{
                        // 标记已经插入的元素的位置 ,-1作为已经插入的较大元素,比较时不计数 
						d[k]=j;
						y[k]=-1;   
						break;
					}
					if(k==0)    // 当大数没有插入点,那就只能在第一位 
					{
						d[k]=j;
						y[k]=-1;
					}
				}
			}

总结:

        这是比较难办的一般算法,当然不一定只能从最大的数开始排列,从最后一位开始也可以,应该有人也会发现,最后一位的数跟实际填入的数是一致的,如果它前面的数比最后一个数小,那前一个填入的数也等于条件给的数。

        其他一些规律可以自行推导和规划,这里就不发散了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值