USTCOJ1381 老式计算器 uva11549 (Set判重、Floyd判圈)

题目链接:http://acm.ustc.edu.cn/ustcoj/problem.php?id=1381
题目来源:uva11549

题目:对于给定的n和k,求k平方,取其高n位数赋值给k,如是不断平方,给出这一运算过程中k可能取到的最大值。
题目分析:显然,对于一个n位整数而言,其可能的取值是有限的,因此上述过程必然出现循环。我们只要在平方过程中得到此前出现过的k值,就表示已经遍历了所有可能的k值。

程序头代码如下

#include<iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
以下两中解法均使用int next(int n, int k)函数来求解k平方的高n位组成的整数。该函数有多中实现方式,见第三节。

解题思路一

将所有出现的k值存起来,并定义一个变量ans存储当前已知的k已取得的最大值。当新产生的k值已出现过,则退出循环,输出ans值。
代码实现,使用stl set存储所有可能的k值。如下:

/*STL Set判重
*by: lance*/
int main()
{
    int t;
    set<int> result;
    scanf("%d", &t);
    while (t--)
    {
        result.clear();
        int n, k;
        scanf("%d%d", &n, &k);
        int ans = k;
        while (result.find(k) == result.end())
        {
            if (ans < k)
                ans = k;
            result.insert(k);
            k = next(n, k);
        }
        printf("%d\n", ans);
    }

    return 0;
}

解题思路二

由于必然出现循环,可使用Floyd判圈算法求解。相关分析可参考: 链表环的检测(Floyd判圈算法)

/*Floyd判圈算法*/
int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        int n, k;
        cin >> n >> k;
        int ans = k;
        int k1 = k, k2 = k;
        do
        {
            k1 = next(n, k1); // 小孩1
            k2 = next(n, k2); // 小孩2,第一步
            if(k2 > ans) ans = k2;
            k2 = next(n, k2); // 小孩2,第二步
            if(k2 > ans) ans = k2;
        }
        while(k1 != k2);   // 追上以后才停止
        cout << ans << endl;
    }
    return 0;
}

next函数实现

在具体的代码代码实现中,求解一个数k的平方的高n位数有多种解法。我们定义该函数为int next(int n, int k)。如下是该函数的几种可能的实现。

/*方案一:
*by: Rujia Liu*/
int buf[100];
int next(int n, int k)
{
    if(!k) return 0;
    long long k2 = (long long)k * k;
    int L = 0;
    while(k2 > 0)
    {
        buf[L++] = k2 % 10;    // 分离并保存k2的各个数字
        k2 /= 10;
    }
    if(n > L) n = L;
    k = 0;
    for(int i = 0; i < n; i++) // 把前min{n,L}位重新组合
        k = k * 10 + buf[--L];
    return k;
}
/*方案二:
* by:ustczz*/
int next(int n, int k)
{
    char str[100] = {0};    //初值为零
    long long k2 = (long long)k * k;
    sprintf(str,"%lld",k2);  //整数转化为字符串
    str[n]='\0';//截取n位
    k=atoi(str);//字符串转化为整数
    return k;
}
/*方案三:
*by: 54whao
*by: lance*/
long long pow10(int e)
{
    long long p = 1;
    while (e--)
        p *= 10;
    return p;
}
int next(int n, int k)
{
    /*通过将变量声明为“静态存储类型”,
    使其可以记录函数上一次调用时的值
    从而避免pow10的重复调用
    */
    static int nflag = -1;
    static long long p;
    if (nflag != n)
    {
        nflag = n;
        p = pow10(n);
    }

    long long k2 = (long long)k * k;
    while (k2 >= p)
        k2 /= 10;
    k = k2;
    return k;
}

你可能感兴趣的:(Floyd判圈算法,老式计算器,Set判重)