回 帖 发 新 帖 刷新版面

主题:第70次编程比赛题目

[size=3]上次比赛冠军得主因为长时间没有再在此发帖子,也联系不到
正好偶有题目,先抢占个位置了。。。

本次比赛题目如下:

[color=Blue]题目描述:[/color]
有n个正整数(4<=n<=13),在这n个正整数之间插入四则运算符,
使得结果恰好等于一个给定的整数值,注意这n个整数的先后顺序不能改变,
不插入运算符的地方的数字直接连起来成一个新数,
如1 2之间不插入运算符则为12,1 2 3之间的话则为整数123
如:1*23-4=19  12+3+4=19

[color=Blue]输入:[/color]
你的程序只需处理一组测试数据,每组第一行1个正整数n
接下来一行为n个小于20的正整数,这n个数和结果连起来总长度小于15位
第三行为要计算出的结果k(-10000<k<10000)

[color=Blue]输出:[/color]
输出1行1个整数,表示解的个数

[color=Blue]样例输入:[/color]
4
1 2 3 4
2

[color=Blue]样例输出:[/color]
2

[color=Blue]其它信息:[/color]
对于样例,只有
1+2+3-4 = 2
1*2*3-4 = 2
两组解
注意 -1+2-3+4=2 这组不合法,只能为四则运算符,不能作为正负号
[color=Red]你需要考虑运算优先级[/color]
题目来源:yzfy无聊改编


比赛结束时间:8月18日 23:00
比赛代码提交方式:直接回复本帖子,回复将隐藏
主要评比内容:代码时间效率
比赛注意事项:必须严格按照要求进行输入输出,不要输出多余的内容
其它:本题提供在线测试,链接[url]http://yzfy.org/dis/listpost.php?tid=897[/url]
如有疑问,请到[url]http://bbs.pfan.cn/post-282271.html[/url]提出
[/size]

回复列表 (共34个回复)

沙发

虽然有代码...不参加了,23日就要去军训...5555555555555

板凳

能加括号么。不加括号难度就小了很多好像

3 楼

不加括号还好玩吗?

4 楼

比赛程序 再那里发?

5 楼

[quote]不加括号还好玩吗?[/quote]


你试试就知道了。

可能你是神牛,不过希望你不要轻视它。

如果你能保证在1h内一次AC(最大数据在1s内通过),我马上拜师。

6 楼

/*
算法分析和设计:

  程序读入数据文件是 myfile.txt, 结果输出在 result.txt中

    计算时,将0 1 2 3 4 分别代替 + - * / 没有运算符号  ,用数字/2表示它的等级, 如: 0 1 是同一等级的,
    只有下一个等级 >=  现有的等级 才会进行运算.
    用五进制的加法产生五进制的数 正好可以 产生全部的 特殊的运算符

  先优先计算出乘除 和 没有运算符的情况, 把结果存放到 数据堆栈 和 运算符堆栈, 在没有乘除的情况下,计算加减法

  由于除法会产生小数, 如果光用整形数据的 会丢失数据, 造成结果不对. 但如果都用浮点数来运算的话,又太浪费空间了.
  本程序是, 将除法的数据单独拿出来, 保留他的余数, 如果最后余数 = 0 并且结果正确, 这输出结果了.
*/
#include <stdio.h>
#include <stdlib.h>

#include "stack.h"

#define N 20
//根据操作符计算出int 型结果返回

stack stack_opnd, stack_optr; // 全局变量, 用做堆栈 存储运算的数据和运算符
FILE *fin, *fout;
int count = 0;  // 记录解的个数

void slove(const int opnd[], const int optr[], int n, int result);
bool read_in(int opnd[], int &opnd_n, int &result);

int main()
{
    // 打开要读入的文件
    if((fin = fopen("myfile.txt", "r")) == NULL)
    {
        printf("打开读入文件出错!" );
        exit(-1);
    }
    
    if((fout = fopen("result.txt", "w")) == NULL)
    {
        printf("打开写入文件出错!" );
        exit(-1);
    }
    
    int opnd_n = 0; // 操作数的个数
    int result = 0; // 添加运算符后的最终结果
    int opnd[N]; // 操作数    
    int optr[N] = {0}; // 操作符, 用特殊的数字代替    

    if( !read_in(opnd, opnd_n, result) )
    {
        printf("读入文件内容发生错误! 请检查文件格式是否正确!\n");
        exit(0);
    }

//    printf("opnd_n:%d ------- result : %d\n", opnd_n, result);
//    return 0;

    while(optr[opnd_n - 2]  < 5) 
    {
        // 产生 opnd_n-1 位 的五进制数 最后一位的数子 > 4 时结束循环, 通过产生五进制数,穷举了所有的运算情况
        init(stack_opnd); // 初始化 数据 和 运算符堆栈
        init(stack_optr);
        if(optr[opnd_n - 2] < 5)
            slove(opnd, optr, opnd_n, result); // 所有数据结果, 和 操作符运算后 的最终结果

        optr[0] ++;     //五进制的最低位 + 1    
        int m = 0;
        while(optr[m] > 4 && optr[opnd_n - 2] < 5) // 低位加1, 是否能产生进位
        {
            optr[m] = 0; //当前位置0, 向前进一位
            optr[++m]++; //高位加1
        }        
    }
    
    fprintf(fout, "总数目 :  %d\n", count); //输出最终结果
    printf("%d\n", count); //输出最终结果
    fclose(fin); //关闭文件
    fclose(fout); //关闭文件
    
    return 0;
}

char trans(int n)
{
    //将数字转换为 运算符
    switch(n)
    {
    case 0:
        return '+';
    case 1:
        return '-';
    case 2:
        return '*';
    case 3:
        return '/';
    case 4:
        return ' ';
    }
    return '#';
}

7 楼


//判断数是否为数据
bool isData(char ch)
{
    if(ch >= '0' && ch <= '9')
        return true;
    return false;
}


bool read_in(int opnd[], int &opnd_n, int &result)
{
    // 从文件中读入数据, opnd[] 为存储数据的数组, opnd_n 为整个的数目, result 为最终的结果

    int cnt = 0;

    char ch = fgetc(fin);
    // 读到第一个数据, 整个操作数的个数
    while(ch != '\n') 
    {
        if(isData(ch)) // 记录第一行的数的数目
            cnt++; 
        while( isData(ch) ) // ch 为数字字符
        {
            opnd_n = opnd_n*10 + (int) (ch - '0');
            ch = fgetc(fin);
        }
        if(ch != '\n')
            ch = fgetc(fin);    // 跳过空格    但不跳过回车
    }
    if(opnd_n > 13 &&  opnd_n < 4  || cnt != 1) // 给定运算 的数目超出范围, 程序结束
    {
        printf("操作数的数目不正确! \n");
        return false;
    }

    // 读到第二行数据, 所有数据    
    ch = fgetc(fin);    // 跳过回车符
    int pos = 0; //存放数据 的标号
    while(ch != '\n')
    {            
        int tmp = 0;        
        while( isData(ch) )  // ch 为数字字符
        {
            tmp = tmp*10 + (int) (ch - '0'); // 计算每一个数字
            ch = fgetc(fin);
        }
        opnd[pos++] = tmp;        

        if(ch != '\n')
            ch = fgetc(fin);    // 跳过空格    但不跳过回车
    }
    if(pos != opnd_n) //输入的 数目 与第一行的数目不同, 程序结束
    {
        printf("第二行输入的数据数目与 第一行的数目不符!\n");
        return false;
    }


    cnt = 0;
    // 读到第三行数据, 最终结果
    ch = fgetc(fin);    // 跳过回车符    
    while(ch != EOF && ch != '\n')
    {
        if(isData(ch)) // 记录第一行的数的数目
            cnt++; 

        while( isData(ch) )  // ch 为数字字符
        {
            result = result*10 + (int) (ch - '0');
            ch = fgetc(fin);
        }
        if(ch != '\n' && ch != EOF)
            ch = fgetc(fin);    // 跳过空格    但不跳过回车
    }

    if(cnt != 1)
    {
        printf("第三行输入的数据不是一个! \n");
        return false;
    }

    return true;
}

8 楼

void slove(const int opnd[], const int optr[], int n, int result)
{
    // opnd 为数据队列, optr 为特殊的运算符队列, n 为参加运算元素的个数,  n - 1 为运算符的个数

    int opnd_pos = 0; // 数据队列的标号
    int optr_pos = 0; // 运算符队列的标号

    push(stack_optr, 9);  // 压入 栈底运算符
    push(stack_opnd, opnd[opnd_pos++]);  // 压入第一个数据

    double div_tmp, rest = 0.0; //余数首先是0.0
    int pre_m = 0; //首先是加法
    int int_tmp; //

    while( optr_pos < n-1 ) // 字符运算队列, 直到最后一个运算符进入了堆栈
    {
        int method1 = optr[optr_pos++]; //下一个运算符
        int method2 = getTop(stack_optr); // 运算符堆栈的第一个运算符

        if(method2 / 2 == 0) //保存除法前的第一个加减号
            pre_m = method2;

        double r_tmp = 0.0; //除后的小数部分
        while(method1 / 2 > 0 && optr_pos <= n-1) 
        {
            //把整个 等级在 1 以上的部分都算完了,直到出现 + 或 - , 由于optr_pos 指向最后一个元素时, optr_pos ++了, 其的最大值是 n-1

            int a =  pop(stack_opnd); // 从堆栈中取出 数据
            int b = opnd[opnd_pos++]; //下一个数据
            if(method1/2 == 1) // 运算符是乘法 或者 除法
            {
                if(method1 == 2) //乘法
                    int_tmp = a * b; 
                else // 除法
                {
                    div_tmp = (a + r_tmp) * 1.0 / b; //处理连除情况, 被除数为 整数部分加 小数部分
                    int_tmp = (int) div_tmp; // 取除后的结果的整数部分
                    r_tmp = div_tmp - int_tmp; //取除后结果的小数部分,
                }                
                push(stack_opnd, int_tmp); // 将整数部分压入堆栈                
            }
            else // 两个数字间 没有运算符的情况
            {
                int tmp = b; //b 的临时备份
                int int_tmp = a;
                while(tmp)
                {
                    int_tmp *= 10;
                    tmp /= 10;
                }
                int_tmp += b;
                push(stack_opnd, int_tmp);
            }
            method1 = optr[optr_pos++]; //下一个运算符
        }

9 楼

//        上一次 除后的余数 存储到 rest 变量中
        if(pre_m == 0) //除号前的符号是 加号
            rest += r_tmp; //余的小数 相加
        else
            rest -= r_tmp;

        while(getTop(stack_optr) != 9) //由于乘除法已经在上部分处理过了, 现在只要处理堆栈中的加减法运算
        {
            method2 = pop(stack_optr); //删除 堆栈中的 第一个运算符                
            int b = pop(stack_opnd);
            int a = pop(stack_opnd);
            if(method2 == 0)
                int_tmp = a + b;
            else
                int_tmp = a - b;
            push(stack_opnd, int_tmp);//将两者计算的结果放到 数据堆栈中去
        }
        push(stack_optr, method1); //压入下一个运算符
        push(stack_opnd, opnd[opnd_pos++]); //压入下一个数据
    }

    while( getTop(stack_optr) != 9 ) //处理剩下来的数据 和 运算符
    {
        int method2 = pop(stack_optr); //删除 堆栈中的 第一个运算符                
        int b = pop(stack_opnd);
        int a = pop(stack_opnd);
        if(method2 == 0)
            int_tmp = a + b;
        else
            int_tmp = a - b;
        push(stack_opnd, int_tmp);//将两者计算的结果放到 数据堆栈中去
    }

    int_tmp = getTop(stack_opnd); // 整数 的结果    
    int r_int = (int) rest; // 把所有余下的小数加后 的整数部分
    rest -=  r_int; // 只留下 余数的小数部分
    int_tmp += r_int; // 最后结果加上 小数的 整数进位
    if(rest == 0.0 && int_tmp == result) //余数的小数部分 = 0, 并且整数部分等于结果
    {
/*
 将满足条件的结果都输出到result.txt
        fprintf(fout, "No: %-3d : %3d", count+1, opnd[0]);
        for(int i = 1; i < n; i++)
        {
            fprintf(fout, "%c", trans(optr[i-1])); //输入文件 运算符
            fprintf(fout, "%3d", opnd[i]); // 输入文件 操作数
        }
        fprintf(fout, " = %3d\n", result);
*/        count++; //计数器加1
    }
}

10 楼

//----stack.h--------
#define MAX 20

struct stack{
    int data[MAX];
    int top;
};

void init(stack &s)
{
    //初始化堆栈
    s.top = -1;
}

bool empty(stack s)
{
    //判断堆栈是否为空,空返回true, 否则返回false;
    return (s.top == -1);
}

int getTop(stack s)
{
    //得到栈顶元素
    if(empty(s))
    {
        printf("该堆栈是空的!\n");
        exit(0);
    }
    return s.data[s.top];
}

void push(stack &s, int elem)
{
    // 向堆栈中,压入elem
    if(s.top == MAX -1)
        {
        printf("堆栈已满,不能再压入数据!\n");
        exit(0);
    }
    s.data[ ++s.top ] = elem;
}

int pop(stack &s)
{
    // 删除堆栈元素
    if(empty(s))
    {
        printf("堆栈已空,不能删除数据\n");
        exit(0);
    }
    return s.data[s.top--];
}

void display(stack s)
{
    for(int i = 0; i <= s.top; i++)
        printf("%3d", s.data[i]);
    printf("\n");
}

我来回复

您尚未登录,请登录后再回复。点此登录或注册