主题:第70次编程比赛题目
雨中飞燕 [专家分:18980] 发布于 2008-08-08 19:21:00
[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]
最后更新于:2008-08-12 12:11:00
回复列表 (共34个回复)
沙发
卧龙孔明 [专家分:240] 发布于 2008-08-10 10:20:00
虽然有代码...不参加了,23日就要去军训...5555555555555
板凳
fenix124 [专家分:70] 发布于 2008-08-11 08:48:00
能加括号么。不加括号难度就小了很多好像
3 楼
abc123!!! [专家分:1080] 发布于 2008-08-11 17:33:00
不加括号还好玩吗?
4 楼
abc123!!! [专家分:1080] 发布于 2008-08-11 19:09:00
比赛程序 再那里发?
5 楼
卧龙孔明 [专家分:240] 发布于 2008-08-12 09:57:00
[quote]不加括号还好玩吗?[/quote]
你试试就知道了。
可能你是神牛,不过希望你不要轻视它。
如果你能保证在1h内一次AC(最大数据在1s内通过),我马上拜师。
6 楼
yj1221 [专家分:20] 发布于 2008-08-14 00:16:00
/*
算法分析和设计:
程序读入数据文件是 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 楼
yj1221 [专家分:20] 发布于 2008-08-14 00:21:00
//判断数是否为数据
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 楼
yj1221 [专家分:20] 发布于 2008-08-14 00:23:00
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 楼
yj1221 [专家分:20] 发布于 2008-08-14 00:23:00
// 上一次 除后的余数 存储到 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 楼
yj1221 [专家分:20] 发布于 2008-08-14 09:05:00
//----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");
}
我来回复