acm_挑战编程:入门

  • 3n+1 问题
/* ************************************** 3n+1问题 ************************************** 从整数n开始,如果n是偶数,把它除以2;如果n是 奇数,把它乘以3加1.用新得到的值重复上述步骤。 直到 n=1 为止。 ************************************** 需要注意: // 1. 中间计算过程会超过 int 或 long (如果 int 或 long 型均为 4 字节存储空间) 型数据所能 // 表示的范围,故需要选择 long long (8 字节存储空间)型整数(除非你使用的算法在做乘的时候不 // 使用一般的乘法,而是使用替代方法实现原数的三倍加一)。 // 2. 输入时可能较大的数在前面,需要调整顺序,这个是导致算法正确却 WA 的重要原因。 // 3. 采用填表的方法保存既往计算结果,可以显著减少计算时间。 ************************************** */

#include <iostream>
using namespace std;

#define min(a, b) ((a) <= (b) ? (a) : (b)) 
#define max(a, b) ((a) >= (b) ? (a) : (b)) 
#define MAXSIZE 10000
int cache[MAXSIZE];

//计算循环长度
int count(long long number)
{
    if(number == 1)
        return 1;
    //模2计算用与计算代替, 除2计算用右移代替
    if(number & 1)
        number += (number << 1)+1;
    else
        number >>= 1;

    //若number存在缓存,则可以利用
    if(number < MAXSIZE)
    {
        if(!cache[number])
            cache[number]=count(number);
        return 1+cache[number];
    }

    return 1+count(number);
}

int main(int ac, char* av[])
{
    int first,second,start,end;
    while(cin>>first>>second){
        //计算上下界
         start = min(first, second);  
        end = max(first, second);  

        //查找最大步长
        int  result=0, steps;
        for(int i=start; i <= end; i++)
            if((steps = count(i)) > result)
                result=steps;
        //
        cout<<first << " " << second << " " << result << endl;  
    }

    return 0;
}
  • 扫雷
// Minesweeper (扫雷) 

// 
// 
// 
// 使用字符数组表示给定的地雷图,逐个扫描统计各点周围的地雷总数。在计算地雷总数时, 
// 用到了一个小技巧,设置边界数组 bounds,将当前的点顺次加上边界数组的值即可得到当前点周围的 8 个 
// 点,注意不要忘记判断点是否在地雷地图范围内。 

#include <iostream> 
#include <cstring> 

using namespace std;  

#define MAXSIZE 100 

inline bool range_checking(int x, int y, int row, int column)  
{  
    return (0 <= x && x < row) && (0 <= y && y < column);  
}  

void display(char matrix[][MAXSIZE], int row, int column)  
{  
    int bounds[8][2] =  
        { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0},  
        {1, 1} };  

    for (int i = 0; i < row; i++)  
    {  
        for (int j = 0; j < column; j++)  
        {  
            // 如果该位置为地雷则原样输出地雷的符号。 
            if (matrix[i][j] == '*')  
                cout << "*";  
            else  
            {  
                // 统计该点周围 8 点的地雷总数。 
                int mines = 0;  
                for (int k = 0; k < 8; k++)  
                {  
                    int m = i + bounds[k][0];  
                    int n = j + bounds[k][1];  

                    if (range_checking(m, n, row, column)  
                        && matrix[m][n] == '*')  
                        mines++;  
                }  

                cout << mines;  
            }  
        }  

        cout << endl;  
    }  
}  

int main(int ac, char *av[])  
{  
    char matrix[MAXSIZE][MAXSIZE];  
    int row, column, field = 0;  

    while ((cin >> row >> column, row && column))  
    {  
        memset(matrix, 0, sizeof(matrix));  

        for (int i = 0; i < row; i++)  
            for (int j = 0; j < column; j++)  
                cin >> matrix[i][j];  

        if (field > 0)  
            cout << endl;  
        field++;  

        cout << "Field #" << field << ":" << endl;  

        display(matrix, row, column);  
    }  

    return 0;  
}  
  • 旅行
// The Trip (旅行)
// PC/UVa IDs: 110103/10137, Popularity: B, Success rate: average Level: 1
// Verdict: Accepted
// Submission Date: 2011-04-09
// UVa Run Time: 0.016s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// 首先计算“平均费用”,即总费用除以学生人数得到的数值,由于是要求支付差距在 1 分钱以内,故可
// 以考虑在计算时取小数点后两位,对于第三位以后的数采用四舍五入的方法,如计算平均值为 9.666
// 666,则取 9.67。那么首先读取正整数n,然后顺序读取n个数值。将所有费用相加,得到平均值。根据题
// 目的要求是“多退少补”,那么可以把学生分成两组,一组是垫付的费用大于平均费用的,一组则是小于等于
// 平均费用的。垫付多的学生应该退还钱款,垫付少的应收取费用。根据题意,需要取最少的那部分。在此,
// 需要注意的是这样的数据:0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,
// 0.01,0.01,0.01,0.01,0.03, 此组数据的平均值为 0.01,但是并不是退还花费了 0.03 美元的
// 那个人 0.02 美元,因为只要满足误差在 1 美分内,所以只需退还花费 0.03 美元的那个人 0.01 美元
// 即可满足所有人花费误差在1美分之内,这个细节可能是大多数人在提交该问题答案所没有注意到的。
//
// 需要注意数据类型的使用,在此题目中,因为每个学生的支出不超过 $100000,如果用单精度浮点数表示,
// 则根据单精度数的定义,能保留 7 位有效数据,但是当学生的总费用超过 $100000.00 以后,则势必出
// 现精度丢失的情况,故需要使用双精度数据,否则结果会不正确。

#include <iostream>

using namespace std;

#define SIZE 1000


double findChange(double *money, int total)  
{  
    double average = 0.0, changeDown = 0.0, changeUp = 0.0, change = 0.0;  

    for (int i = 0; i < total; i++)  
        average += money[i];  

    average /= total;  
    average = (long) (average * 100 + 0.5) / 100.00;  

    for (int i = 0; i < total; i++)  
    {  
        if (money[i] > average)  
            changeUp += (money[i] - average);  
        else  
            changeDown += (average - money[i]);  
    }  

    if (changeDown > 0 && changeUp > 0)  
    {  
        if (changeDown > changeUp)  
            change = changeUp;  
        else  
            change = changeDown;  
    }  
    else  
    {  
        if (changeUp == 0 && changeDown == 0)  
            change = 0.0;  
        else  
        {  
            if (changeDown == 0)  
            {  
                for (int i = 0; i < total; i++)  
                    if (money[i] > average)  
                        change +=  
                            (money[i] - average -  
                            0.01);  
            }  
            else  
            {  
                for (int i = 0; i < total; i++)  
                    if (money[i] < average)  
                        change +=  
                            (average - money[i] -  
                            0.01);  
            }  
        }  
    }  

    return change;  
}  

int  main(int ac, char* av[])
{
    int total;
    double money[SIZE], result=0.0;


    while(cin>>total,total){
        for (int i = 0; i < total; i++)  
            cin >> money[i];  
         result = findChange(money, total);  

        cout.precision(2);  
        cout.setf(ios::fixed | ios::showpoint);  
        cout << "$" << result << endl;  
    }

}
  • 液晶显示屏
// LC-Display (液晶显示屏)
// PC/UVa IDs: 110104/706, Popularity: A, Success rate: average Level: 1
// Verdict: Accepted 
// Submission Date: 2011-04-09
// UVa Run Time: 0.012s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net

#include <iostream>
#include <cstring>

using namespace std;

#define MAXLENGTH 8

void lcd_display (long size, long number)
{
    // 将number拆分为单个的数字。
    int digits[MAXLENGTH];

    memset (digits, -1, sizeof (digits));
    if (number == 0)
        digits[MAXLENGTH - 1] = 0;
    else
    {
        for (int i = MAXLENGTH - 1; number > 0; i--)
        {
            digits[i] = number % 10;
            number /= 10;
        }
    }

    // 定义每个数字的关键笔划。
    string outline[5][10] = { 
        " - ", " ", " - ", " - ", " ", " - ", " - ", " - ", " - ", " - ",
        "| |", " |", " |", " |", "| |", "| ", "| ", " |", "| |", "| |",
        " ", " ", " - ", " - ", " - ", " - ", " - ", " ", " - ", " - ",
        "| |", " |", "| ", " |", " |", " |", "| |", " |", "| |", " |",
        " - ", " ", " - ", " - ", " ", " - ", " - ", " ", " - ", " - "
    };

    // 根据指定size将关键笔划扩大显示,实际上就是将关键笔划重复size次。
    for (int row = 1; row <= (2 * size + 3); row++)
    {
        for (int i = 0; i < MAXLENGTH; i++)
            if (digits[i] != -1)
            {
                string line;
                if (row == 1)
                    line = outline[0][digits[i]];
                if (2 <= row && row < (size + 2))
                    line = outline[1][digits[i]];
                if (row == (size + 2))
                    line = outline[2][digits[i]];
                if ((size + 3) <= row && row <= (2 * size + 2))
                    line = outline[3][digits[i]];
                if (row == (2 * size + 3))
                    line = outline[4][digits[i]];

                // 输出关键笔划。
                cout << line[0];
                for (int j = 0; j < size; j++)
                    cout << line[1];
                cout << line[2];

                // 在两个数字间要有一列空行。
                if (i < (MAXLENGTH - 1))
                    cout << " ";
            }
        cout << '\n';
    }
}

int main (int ac, char *av[])
{
    long size, number;

    while ((cin >> size >> number, size || number))
    {
        lcd_display (size, number);
        cout << endl;
    }

    return 0;
}

你可能感兴趣的:(acm_挑战编程:入门)