【USACO题库】2.3.3 Zero Sum和为零

题目描述

请考虑一个由1到N(N=3, 4, 5 ... 9)的数字组成的递增数列:1 2 3 ... N。
现在请在数列中插入“+”表示加,或者“-”表示减,抑或是“ ”表示空白,来将每一对数字组合在一起(请不在第一个数字前插入符号)。计算该表达式的结果并注意你是否得到了和为零。请你写一个程序找出所有产生和为零的长度为N的数列。

INPUT FORMAT
单独的一行表示整数N (3 <= N <= 9)。

SAMPLE INPUT (file zerosum.in)
7

OUTPUT FORMAT
按照ASCII码的顺序,输出所有在每对数字间插入“+”, “-”, 或 “ ”后能得到和为零的数列。(注意:就算两个数字之间没有插入符号也应该保留空格)

SAMPLE OUTPUT (file zerosum.out)
1+2-3+4-5-6+7
1+2-3-4+5+6-7
1-2 3+4+5+6+7
1-2 3-4 5+6 7
1-2+3+4-5+6-7

1-2-3-4-5+6+7



这道题目一看就知道是搜索,可是搜完之后应该如何计算这个式子的值呢?

因为这里多了一个' ',所以我们就需考虑这个,然而这个应该是优先的,意思就是说要先算这一个.当我们用b数组来存每个数时,一个数的左边以及右边都不为' ',才不是“优先”的,就可以记录下来了,然后再记录空格的sum,最后用ans来存储答案。

代码:

var
        n,i,sum,ans,w:Longint;
        a:array[0..9] of char;
        b:array[1..9] of longint;
procedure print;
begin
        for i:=1 to n-1 do
                write(i,a[i]);
        writeln(n);
end;
procedure dfs(k:Longint);
begin
        if k=n then
        begin
                fillchar(b,sizeof(b),0);
                for i:=1 to n do
                        if (a[i]<>' ') and (a[i-1]<>' ') then b[i]:=i;
                sum:=1;
                w:=0;
                for i:=1 to n do
                        if a[i]=' ' then
                        begin
                                sum:=sum*10+i+1;
                                if w=0 then w:=i;
                        end
                        else
                        begin
                                if w<>0 then
                                begin
                                        b[w]:=sum;
                                        w:=0;
                                end;
                                sum:=i+1;
                        end;
                ans:=b[1];
                for i:=1 to n-1 do
                begin
                        if a[i]='+' then ans:=ans+b[i+1];
                        if a[i]='-' then ans:=ans-b[i+1];
                end;
                if ans=0 then print;
                exit;
        end;
        a[k]:=' ';
        dfs(k+1);
        a[k]:='+';
        dfs(k+1);;
        a[k]:='-';
        dfs(k+1);
end;

begin
        readln(n);
        dfs(1);
end.


当然,这道题也有别的方法,我们可以考虑不在全部枚举完之后再计算值,可以边枚举边算:

sum表示当前总和,rest表示的是当前连数的和。(这里需要注意,rest的和不止是代表当前连续数字的和,当没有' '的时候,rest也会代表着下一个要加减的数,这样可以方便sum计算)如果是' '就只需更新rest,否则如果是加的话,先加上rest,因为rest如果是负数,加上一个负数也是一样的,然后在+,-的时候判断rest是往正数还是负数更新(这个地方是重点,也是简便之处)(另外递归符号的顺序一定得是' ','+','-',题目输出顺序)

var
        n,i:LOngint;
        a:array[1..9] of char;
Procedure print;
begin
        for i:=1 to n-1 do
                write(i,a[i]);
        writeln(n);
end;

Procedure dfs(sum,rest,k:Longint);
begin
        if k=n then
        begin
                if sum+rest=0 then print;
                exit;
        end;

        a[k]:=' ';
        if rest<0 then
                dfs(sum,rest*10-k-1,k+1)
        else
                dfs(sum,rest*10+k+1,k+1);

        a[k]:='+';
        dfs(sum+rest,k+1,k+1);;
        a[k]:='-';
        dfs(sum+rest,-(k+1),k+1);
end;

begin
        readln(n);

        dfs(0,1,1);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值