鸽了很多天,忙了一堆乱七八糟的事情,现在静下心来,重新做一下这题——背景(咕咕)
题目贴在这里:
设有一个整形数组 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;
}
}
}
总结:
这是比较难办的一般算法,当然不一定只能从最大的数开始排列,从最后一位开始也可以,应该有人也会发现,最后一位的数跟实际填入的数是一致的,如果它前面的数比最后一个数小,那前一个填入的数也等于条件给的数。
其他一些规律可以自行推导和规划,这里就不发散了。