读书人

求一路算法题

发布时间: 2012-11-05 09:35:11 作者: rapoo

求一道算法题
题目是这样的,已知一个整数集合T,集合中可以包括0到9之间任意数,集合中数字不重复。现在给出一个整数N,大小按int类型,算法要求是:从上面集合中取出数字所能组成的整数中,比给出的N大的集合里面,最小的那个整数。比如,整数集合T=『1,2,3』,整数N=300,那么要从集合中取出数字所组成的整数应该是311;再如:T=『1』,N=56,那么要得到的整数应该是111(也就是说集合里面的数可以取多次);

多谢大家能给点儿想法。

[解决办法]
首先不妨设定N=a1a2a3...aM,M位,集合为T

从最高位a1看起,一直看到最后一位aM

(1)在此过程中,一旦有一位(设为ai),满足ai>max{Tj},也就是ai大于集合T中所有的元素,则停止探寻,只需要

在集合T中构造出M+1位的最小的数,即为所求。

(2)在此过程中,一旦有一位(设为ai),满足ai<max{Tj},也就是ai小于集合T中所有的元素,则可判定所求的数

也是M位,则继续探寻下面的数,且从ai这一位开始满足这样的法则,在T中找到比ai大的元素中最小的元素k,找出

以k为首位的位数等于(M-i+1)的最小数,作为所求数的后(M-i+1)位数

(3)在此过程中,一旦有一位(设为ai),满足ai=max{Tj},则继续探寻。当然,如果是对应刚才的(2),则所求的数的前(i-1)位都为max{Tj},也就是保留作为所求数的一部分,继续往下看。如果是对应刚才的情况(1),就是暂时放到那里,继续往下看(我相信到底该怎么解决这两种情况只是一个技巧问题,程序中你应该能解决)

下面给你几个例子
N=55557 T={1,2,4,5}
从N的最高位5看,一直对应情况3,直到7,7>5,所以归到情况1,所求的数应该为111111
N=555278 T={1,2,4,5}
从N的最高位5看,一直对应情况3,直到2,2<5,所以归到情况2,所求的数应该为555411

[解决办法]
从右往左搜貌似会快一点

如果aM < max{Tj} 则调整aM为刚好比aM大的集合中的数字就OK了
如果aM >= max{Tj} 则继续看高一位aM-1
如果aM-1 < max{Tj} 则调整aM-1为刚好比aM-1大的集合中的数字,aM为集合中最小的数字
如果aM-1 >= max{Tj} 则继续看高一位aM-2
。。。。。。
直到a1
如果1 < max{Tj} 则调整aM-1为刚好比1大的集合中的数字,a1后的数字都为为集合中最小的数字
如果a1 >= max{Tj} 则有M+1位且都为集合中最小的数字

[解决办法]

探讨

首先不妨设定N=a1a2a3...aM,M位,集合为T

从最高位a1看起,一直看到最后一位aM

(1)在此过程中,一旦有一位(设为ai),满足ai>max{Tj},也就是ai大于集合T中所有的元素,则停止探寻,只需要

在集合T中构造出M+1位的最小的数,即为所求。

(2)在此过程中,一旦有一位(设为ai),满足ai<max{Tj},也就是ai小于集合T中所有的元素,则可判……

[解决办法]
探讨
首先不妨设定N=a1a2a3...aM,M位,集合为T

从最高位a1看起,一直看到最后一位aM

(1)在此过程中,一旦有一位(设为ai),满足ai>max{Tj},也就是ai大于集合T中所有的元素,则停止探寻,只需要

在集合T中构造出M+1位的最小的数,即为所求。

(2)在此过程中,一旦有一位(设为ai),满足ai<max{Tj},也就是ai小于集合T中所有的元素,则可判定……

[解决办法]
探讨

引用:
首先不妨设定N=a1a2a3...aM,M位,集合为T

从最高位a1看起,一直看到最后一位aM

(1)在此过程中,一旦有一位(设为ai),满足ai>max{Tj},也就是ai大于集合T中所有的元素,则停止探寻,只需要

在集合T中构造出M+1位的最小的数,即为所求。

(2)在此过程中,一旦有一位(设为ai),满足ai<max{T……

[解决办法]
7楼说的有道理,是得修改一下 构造一个栈
设定N=a1a2a3...aM,M位,集合为T

从a(1)开始从左向右扫描,在此过程中,
(1)如果ai属于T,则先将ai入栈
(2)如果ai不属于T
((1)) a(i)>max{Tj}则从栈中弹出元素b,直到b=a(k)<max{Tj},则找出

T中比b大的最小元素c,以c为首位构造M-k+1位最小数,充当最终结果的后

M-k+1位,而栈中的k-1位个数依次出栈充当前k-1位,组合而成最终的结

果. 如果当要弹出下一个元素时栈为空,则可断定所求结果

为M+1位的最小数
((2))a(i)<max{Tj},则在T中找到比ai大的元素中最小的元素c,找出

以c为首位的位数等于(M-i+1)的最小数,作为所求数的后(M-i+1)位

数,从栈中依次弹出所有元素作为最终结果的前i-1位
大家再看看喽



[解决办法]
将标准数A拆分成每个10进制的位,例如:146 拆分成1,4,6
如果最后一位大于当前集合中的最大值,则它的上一位加1。
如:集合元素为[1 2 3],标准数为 146,拆分为 1,4,6,在判断时,应这样做
因为6 > 集合中的最大数 3,则 1,4,6 转换成 1,5,0
因为5 > 集合中的最大数 3,则 1,5,0 转换成 2,0,0
以此类推。如果最高位 > 集合中的最大数 3,则需要进一位,标记为1,0,0,0,在这个例子中没有出现这种情况。
下一步,我们匹配每一位,在集合中找到小于等于它的数中最接近它的,就可以输出了。这个例子的输出为211


[解决办法]
/*
程序只考虑了处理逻辑,结构可以稍微修饰一下
*/


#include <iostream>
using namespace std ;

// A中最小元素
int SmallestElem(char A[], int n)
{
return A[0] ;
}

// 获得在集合A中,>=ai的最小元素,如果不存在,返回-1
int GetSmallest_EqaualLargerThanAi(char A[], int n, int ai)
{
int i = 0 ;
for(; i<n; i++)
{
if(A[i] >= ai)
break ;
}
return i==n?-1:A[i] ;
}
// 将结果B中从s到e的设置为A集合中最小元素
int SetLowerB(char B[], int s, int e, char A[], int an)
{
for(; s<e; s++)
{
B[s] = SmallestElem(A, an) ;
}
}

// 递归过程
int Recursion(char A[], int an, char N[], int nn, int i, char B[])
{
if (i<nn)
{
int ai = N[i] ; // 当前位
int si = GetSmallest_EqaualLargerThanAi(A, an, ai) ;// 获得>=ai的元素
if(si == -1) // 需要 “进位”
{
SetLowerB(B, i, nn, A, an) ; // 设置后续为最小元素
return 1 ; // 进位返回1
}
int res = Recursion(A, an, N, nn, i+1, B) ; // 递归处理后续位数,res=1表示后续位数产生“进位”
si = GetSmallest_EqaualLargerThanAi(A, an, si+res) ;
if (si == -1)
{
SetLowerB(B, i, nn, A, an) ;
return 1 ;
}
else
{
B[i] = si ;
return 0 ; // 没有“进位”
}
}
return 0 ;
}
// 辅助函数
void Output(char B[], int n)
{
for(int i=0; i<n && B[i]!='F'; i++)
{
std::cout<<B[i];
}
std::cout<<endl ;
}

int main(void)
{
char A[] = {'1','2','3'} ;
char N[] = {'3','4','4'} ;
char B[100] ;
for(int i=0; i<sizeof(B); i++)
{
B[i] = 'F' ;
}

int res = Recursion(A, sizeof(A)/sizeof(char), N, sizeof(N)/sizeof(char), 0, B) ;
if(res == 1)// 最高位需要“进位”
std::cout<<"1" ;
Output(B, sizeof(B));

return 0 ;
}

[解决办法]
我搞了半天终于写出来了,应该没多大问题。

#include<iostream>
#include<stdlib.h>

using namespace std;

int comp(const void *p, const void *q)
{
return ( *(int*)p > *(int*)q );
}

void Divide(int Digit[], int X, int &N)
{
while(X > 0)
{
Digit[N++] = X % 10;
X /= 10;
}
}

int Sum(int Set[], int pos, int N)
{
int val = 0;

for(int i = 0; i < N; i ++)
{
val = 10 * val + Set[pos];
}

return val;
}

bool Check(int rec[], int Digit[], int pos, int n)
{
for(int i = 0; i < pos; i ++)
{
if(rec[i] > Digit[n-1-i])
{
return true;
}
}

return false;
}

void Find(int Set[], int m, int Digit[], int pos, int n, int &min, int X)
{
static int sum = 0;
static int rec[10];

if(pos == n && sum != X)
{
min = min < sum ? min : sum;
}

for(int i = 0; i < m; i ++)
{
if(pos < n && ( Set[i] >= Digit[n-1-pos] //当前位 >= X对应位上的数字
|| pos > 0 && Check(rec, Digit, pos, n) )) //如果高位已经存在大于X对应位上的数字,则下一位只需要用最小的数字
{
sum = 10 * sum + Set[i];
rec[pos] = Set[i];

Find(Set, m, Digit, pos+1, n, min, X);

rec[pos] = -1;
sum /= 10;
}
}
}

void main()
{
int Set[4] = {1, 2, 3, 4};
int Digit[10];
int X = 3468;
int M = sizeof(Set) / sizeof(*Set);
int N = 0;

qsort(Set, M, sizeof(int), comp);

Divide(Digit, X, N);

int min = Sum(Set, M-1, N);


if(min <= X)
{
cout << Sum(Set, 0, N+1) << endl;
}
else
{
Find(Set, M, Digit, 0, N, min, X);

cout << min << endl;
}
}

[解决办法]
我靠,怎么没人回帖?全挂了?

读书人网 >软件架构设计

热点推荐