回 帖 发 新 帖 刷新版面

主题:[讨论]第33次编程比赛第1题题目

出个还算简单的,欢迎广大编程爱好者参加!
结果为0的序列:
      考虑由1到n(n<=9)按递增顺序排成的序列1234...n,在他们之间加入加号,减号或者什么也不加,分别使它们做加法,减法或者将数字合并.然后求出结果,看看是否为0.
      写一个程序,找出所有长度为n的结果为0的序列,返回序列的个数.
      函数接口: int ResultIsZero(int n);
      其中n表示序列的长度, int表示返回的序列的个数.
举例:
      n = 8, 返回10.
序列分别为:1+2+3+4-5-6-7+8 = 0;
           1+2+3-4+5-6+7-8 = 0;
           1+2-3+4+5+6-7-8 = 0;
           1+2-3-4-5-6+7+8 = 0;
           1-2+3-4-5+6-7+8 = 0;
           1-2-3+4+5-6-7+8 = 0;
           1-2-3+4-5+6+7-8 = 0;
           1+23-45+6+7+8 = 0;
           12-34-56+78 = 0;
           1-23-4+5+6+7+8 = 0;

      有疑问请到讨论帖讨论!
http://www.programfan.com/club/showbbs.asp?id=178473

回复列表 (共8个回复)

沙发

祝大家好运!

板凳

/*出个还算简单的,欢迎广大编程爱好者参加!
结果为0的序列:
      考虑由1到n(n<=9)按递增顺序排成的序列1234...n,在他们之间加入加号,减号或者什么也不加,分别使它们做加法,减法或者将数字合并.

然后求出结果,看看是否为0.
      写一个程序,找出所有长度为n的结果为0的序列,返回序列的个数.
      函数接口: int ResultIsZero(int n);
      其中n表示序列的长度, int表示返回的序列的个数.
举例:
      n = 8, 返回10.
序列分别为:1+2+3+4-5-6-7+8 = 0;
           1+2+3-4+5-6+7-8 = 0;
           1+2-3+4+5+6-7-8 = 0;
           1+2-3-4-5-6+7+8 = 0;
           1-2+3-4-5+6-7+8 = 0;
           1-2-3+4+5-6-7+8 = 0;
           1-2-3+4-5+6+7-8 = 0;
           1+23-45+6+7+8 = 0;
           12-34-56+78 = 0;
           1-23-4+5+6+7+8 = 0;

*/
#include <iostream>
using namespace std;

void showcode(int code,int n)
{
    int i;
    cout<<"  ";
    for(i=0;i<9;i++)
        cout<<i+1<<"  ";
    cout<<"\n  ";
    for(i=0;i<n;i++){
        cout<<(code & 0x1)<<"  ";
        code >>= 1;
    }
    cout<<endl;
}

class CCode{
private:
    int code;
    int n;
    int num[9];//转化为数字
    int max;
    int sum;
    int count;
public:
    CCode(){};
    CCode(int code,int n);
    int number(int start,int end);
    int cacl();
    int check(const int potcode);
    void show();
};

CCode::CCode(int ncode,int nn)
{
    code = ncode;
    n = nn;
    max = 0;
    sum = 0;
    count = 0;
    int end = 0,start = 1;
    while(ncode){
        end++;
        if(ncode & 0x1){
            num[count] = number(start,end);
            sum += num[count];
            max = (num[count] > max) ? num[count] : max;
            count++;
            start = end + 1;
        }
        ncode >>= 1;
    }
}

int CCode::number(int start,int end)
{
    int i;
    int result = 0;
    for(i = start;i<=end;i++){
        result *= 10;
        result += i;
    }
    return result;
}

int CCode::check(const int npotcode)
{
    int potcode = npotcode;
    int positive = num[0];//正数和
    int negative = 0;//负数和
    int i = 0;
//    int t[9] = {0};

//    cout<<"运算符code:\n";
//    showcode(potcode,count-1);    
    for(i=1;i<count;i++){
//        t[i] = potcode & 0x1;
        if(potcode & 0x1)
            positive += num[i];
        else
            negative += num[i];
        potcode >>= 1;
    }
//显示算式
/*    
    if(positive == negative){
        cout<<"算式:"<<num[0];
        for(i=1;i<count;i++){
            if(t[i])
                cout<<" + ";
            else
                cout<<" - ";
            cout<<num[i];
        }
        cout<<" = "<<positive - negative<<endl;
    }
*/
    return positive - negative;
}

int CCode::cacl()
{
    if(sum < max + max || count<3)
        return 0;
    int result = 0;
    int potcode = 1 << (count - 1);
    while(potcode--){
        if(check(potcode) == 0)
            result ++;
    }
    return result;
}

void CCode::show()
{
    int i;
    cout<<"\n显示数据:\n  ";
    cout<<"code为:"<<code<<endl;
    showcode(code,n);
    cout<<"  数字为:\n  ";
    for(i=0;i<count;i++){
        cout<<num[i]<<"  ";
    }
    cout<<endl;
    cout<<"共有 "<<count<<" 个数字,其中最大值为:"<<max<<" ,和为:"<<sum<<endl;
}

int ResultIsZero(int n)
{
    if(n>9 || n<=2)
        return 0;
    //要使结果 == 0,须将序列分为3 - n 部分

    int code = 1 << n;            //01序列
    int end = 1 << (n-1);
    int result = 0;                //满足条件的序列个数
    while(--code > end){
        if(code == 10)
            cout<<"";
        CCode ccode(code,n);
//        ccode.show();
        result += ccode.cacl();    
    }
    return result;
}

int main (void)
{
    cout<<"\n";
    int i;
    for(i=0;i<10;i++){
        cout<<"\n i = "<<i<<endl;
        cout<<"共有:"<<ResultIsZero(i)<<"个"<<endl;
    }    
    return 0;
}

3 楼

#include <iostream>
using namespace std;

bool daji(int a[],int x,bool bl[])
{
    int temp = a[0];
    for(int i = 0; i < x; i++)
    {
    if(bl[i])
        temp += a[i+1];
    else
        temp -= a[i+1];
    }
    if(!temp)
        return true;
    return false;
}

int fu(bool bl[],int i,int a[],int x)
{
    if(i == x)
        return daji(a,x,bl);
    int m = 0;
    bl[i] = true;
    m += fu(bl,i+1,a,x);
    bl[i] = false;
    m += fu(bl,i+1,a,x);
    return m;
}

int suan(int a[],int x)
{
    if(x == 1)
        return 0;
    bool *bl = new bool[x-1];
    return fu(bl,0,a,x-1);
}

int m10(int n)
{
    if(n == 0)
        return 1;
    int  temp = 10;
    for(int i = 1; i < n; i++)
        temp *= 10;
    return temp;
}

int shuz(int a[],int i,int n,int x)
{
    if(i > n)
        return suan(a,x);
    int temp;
    int w = 0;
    for(int j = 1; j <= (n-i+1); j++)
    {
        temp = 0;
        for(int k = j; k > 0; k--)
            temp += (i+j-k)*m10(k-1);
        a[x] = temp;
        w += shuz(a,i+j,n,x+1);
    }
    return w;
}

int ResultIsZero(int n)
{
    if(n < 3)
        return 0;
    int a[9];
    return shuz(a,1,n,0);
}

4 楼

/*
程序介绍

采用深度优先搜索。
当n==N时返回。
时间复杂度:O(3^N)

三个参数的意义:
n:    表示目前分析到第n个数字,n=0表示第一个。
       开始递归时n=1,即是说从数字2开始。(因为数字1始终都放在最前,不加符号)
total:表示目前为止得到的计算结果。但不包括last中的值,因为last还可能变化。
last: 表示从上一个数字开始到最后一次出现+-符号,已经形成的数。
       例如,分析到123+45-678时,last=678
current变量:记录当前正在处理的数字的值,正好是n+1。
*/

//===================================================================
// 程序代码

static int N;

static int ResultIsZero_DFS(int n, int total, int last)
{
    const int current = n+1;
    if( n == N )
        return (total+last == 0);
    else
        return
          ResultIsZero_DFS(n+1, total, last*10+current)
        + ResultIsZero_DFS(n+1, total+last, current)
        + ResultIsZero_DFS(n+1, total-last, current);
}

int ResultIsZero(int n)
{
    N = n;
    return ResultIsZero_DFS(1, 0, 1);
}

//===================================================================
// 以下代码为测试用

#include <iostream>
using std::cout;
using std::endl;

int main(void)
{
    int i;
    // 正确性测试
    for(i=1; i<=9; ++i)
        cout << i << '\t' << ResultIsZero(i) << endl;
    // 效率测试
    cout << "效率测试开始" << endl;
    for(i=0; i<3000; ++i)
        ResultIsZero(9);
    cout << "效率测试结束" << endl;
    return 0;
}

5 楼

/*出个还算简单的,欢迎广大编程爱好者参加!
结果为0的序列:
      考虑由1到n(n<=9)按递增顺序排成的序列1234...n,在他们之间加入加号,减号或者什么也不加,分别使它们做加法,减法或者将数字合并.然后求出结果,看看是否为0.
      写一个程序,找出所有长度为n的结果为0的序列,返回序列的个数.
      函数接口: int ResultIsZero(int n);
      其中n表示序列的长度, int表示返回的序列的个数.
举例:
      n = 8, 返回10.
序列分别为:1+2+3+4-5-6-7+8 = 0;
           1+2+3-4+5-6+7-8 = 0;
           1+2-3+4+5+6-7-8 = 0;
           1+2-3-4-5-6+7+8 = 0;
           1-2+3-4-5+6-7+8 = 0;
           1-2-3+4+5-6-7+8 = 0;
           1-2-3+4-5+6+7-8 = 0;
           1+23-45+6+7+8 = 0;
           12-34-56+78 = 0;
           1-23-4+5+6+7+8 = 0;

*/
#include <iostream>
using namespace std;

void showcode(int code,int n)
{
    int i;
    cout<<"  ";
    for(i=0;i<9;i++)
        cout<<i+1<<"  ";
    cout<<"\n  ";
    for(i=0;i<n;i++){
        cout<<(code & 0x1)<<"  ";
        code >>= 1;
    }
    cout<<endl;
}

class CCode{
private:
    int code;
    int n;
    int num[9];//转化为数字
    int max;
    int sum;
    int count;
public:
    CCode(){};
    CCode(int code,int n);
    int number(int start,int end);
    int cacl();
    bool check(const int potcode);
    void show();
};

CCode::CCode(int ncode,int nn)
{
    code = ncode;
    n = nn;
    max = 0;
    sum = 0;
    count = 0;
    int end = 0,start = 1;
    while(ncode){
        end++;
        if(ncode & 0x1){
            num[count] = number(start,end);
            sum += num[count];
            max = (num[count] > max) ? num[count] : max;
            count++;
            start = end + 1;
        }
        ncode >>= 1;
    }
}

int CCode::number(int start,int end)
{
    int i;
    int result = 0;
    for(i = start;i<=end;i++){
        result *= 10;
        result += i;
    }
    return result;
}

bool CCode::check(const int npotcode)
{
    int potcode = npotcode;
    int positive = num[0];//正数和
//    int negative = 0;//负数和
    int i = 0;
//    int t[9] = {0};

//    cout<<"运算符code:\n";
//    showcode(potcode,count-1);    
    for(i=1;i<count;i++){
//        t[i] = potcode & 0x1;
        if(potcode & 0x1)
            positive += num[i];
//        else
//            negative += num[i];
        potcode >>= 1;
    }
//显示算式
/*    
    if((positive<<1) == sum){
        cout<<"算式:"<<num[0];
        for(i=1;i<count;i++){
            if(t[i])
                cout<<" + ";
            else
                cout<<" - ";
            cout<<num[i];
        }
        cout<<" = "<<(positive<<1) - sum<<endl;
    }
*/
//    return positive - negative;
    return (positive<<1) == sum;
}

int CCode::cacl()
{
    //总和为奇数
    if(sum & 1)
        return 0;
    if((sum>>1) < max || count<3)
        return 0;
    int result = 0;
    int potcode = 1 << (count - 1);
    while(potcode--){
        if(check(potcode))
            result ++;
    }
    return result;
}

void CCode::show()
{
    int i;
    cout<<"\n显示数据:\n  ";
    cout<<"code为:"<<code<<endl;
    showcode(code,n);
    cout<<"  数字为:\n  ";
    for(i=0;i<count;i++){
        cout<<num[i]<<"  ";
    }
    cout<<endl;
    cout<<"共有 "<<count<<" 个数字,其中最大值为:"<<max<<" ,和为:"<<sum<<endl;
}

int ResultIsZero(int n)
{
    if(n>9 || n<=2)
        return 0;
    //要使结果 == 0,须将序列分为3 - n 部分

    int code = 1 << (n-1);            //01序列
    int end = 1 << n;
    int result = 0;                //满足条件的序列个数
    while(++code < end){
//        if(code == 10)
//            cout<<"";
        CCode ccode(code,n);
//        ccode.show();
        result += ccode.cacl();    
    }
    return result;
}

int main (void)
{
    cout<<"\n";
    int i;
    for(i=0;i<10;i++){
        cout<<"\n i = "<<i<<endl;
        cout<<"共有:"<<ResultIsZero(i)<<"个"<<endl;
    }    
    return 0;
}

6 楼

请问,如何隐藏内容

7 楼

下面是我刚刚完成的一个程序,在VC++6.0调试通过

// 33thmatch2.cpp : Defines the entry point for the console application.
//
//#include "stdafx.h"

#include "stdlib.h"
#include "stdio.h"

#define MAX_LEN  9

struct st_str
{
    char *p;    //字符串的开始地址
    int len;    //字符串的长度
};

/*
g:全局变量,表示数字串的一种切分
若len=3,lenArray[0]=3,lenArray[1]=1,lenArray[2]=4 
则表示数字串被切分为3段,其它每段长度为3,1,4,
各段数字串为"123","4","5678"
*/
struct 
{
    int   len;                            //'12345678"被分为len段
    char  lenArray[MAX_LEN];            //表示各段长度的数组
    struct st_str strTable[MAX_LEN];    //表示各段数字串的数组
    char  signArray[MAX_LEN];            //符号数组,signArray[i]为'+'或者'-'
}g;


char digArray[MAX_LEN]=
{
    '1','2','3','4','5','6','7','8','9'
};

//将长为len,地址为p的字符串转化为数
int str2num(char *p,int len) 
{
    int i,n;
    for (n=0,i=0;i<len;i++)
    {
        n*=10;
        n+= (p[i]-'0');
    }
    return n;
}

void printfExpression(int result)
{
    int i,j;
    for (j=0;j<g.strTable[0].len;j++)
        printf("%c",g.strTable[0].p[j]);
    
    for (i=0;i<g.len-1;i++)
    {
        printf("%c",g.signArray[i]);

        for (j=0;j<g.strTable[i+1].len;j++)
            printf("%c",g.strTable[i+1].p[j]);
    }
    printf("=%d\n",result);
}

//检查某一种数字串切分是含有运算结果为0的表达式,返回表达式的个数
int check()
{
    int i,n,count,r,r2,mask;
    int zeroExpCount; //结果等于0的表达式的个数
    
    // 共有g.len-1 个'+','-',其排列方式有count种
    count= (1<<(g.len-1));
    for (zeroExpCount=0,n=0;n<count;n++)
    {
        /*
        以下的代码得到一种'+'和'-'的组合,
        类似于将n转化为二进制数,只不过,这里用'+'表示'0',用'-'表示'1',
        */
        for (i=0;i<g.len-1;i++)
        {
            mask=(1 << i);
            if ( (n & mask)==0 )
                g.signArray[i]='+';
            else
                g.signArray[i]='-';
        }
    
        //计算表达式的结果
        r=str2num(g.strTable[0].p,g.strTable[0].len);
        for (i=0;i<g.len-1;i++)
        {
            // r2: 第二操作数字
            r2=str2num(g.strTable[i+1].p,g.strTable[i+1].len);

            if (g.signArray[i]=='+')
                r+= r2;
            else
                r-= r2;
        }
        if (r==0)
        {
            //printfExpression(r);//如果想打印这个表达式,请打开这语句
            zeroExpCount++;
        }
    }
    return zeroExpCount;
}

//递归函数,得到所有数字切分的组合
// 参数level:已经切分出来的各个数的个数
// *pCount: 符合条件的表达式的个数
// n,数字的个数,
void    getAllCombo(int n,int *pCount,int level)
{
    static int ret;
    char *p;
    int i,totalLen,len;
    
    for (totalLen=0,i=0;i<level;i++)
        totalLen+=g.lenArray[i];
    
    if (totalLen==n) //得到一种切分
    {
        g.len=level;
        //-----计算strTable----
        for (p=digArray,i=0;i<level;i++)
        {
            g.strTable[i].p=p;
            g.strTable[i].len=g.lenArray[i];
            p+=g.lenArray[i]; 
        }
        if (level>1) //得到一种有效的切分
           *pCount+=check(); //检查可组成运算结果等于0的表达式的个数
    }
    else
    {
        for (i=1;i<=n-totalLen;i++)
        {
            g.lenArray[level]=i;
            getAllCombo(n,pCount,level+1);//求下一段切分 
        }
    }
}    

int ResultIsZero(int n)
{
    int r=0;
    getAllCombo(n,&r,0);
    return r;
}

int main(int argc, char* argv[])
{
    int count,n;
    printf("plese input a num n(2<=n<=9)");
    scanf("%d",&n);
    if (n<2 || n>9)
        return 0;

    count=ResultIsZero(n);

    printf("总共有%d种符合条件的表达式\n",count);
    return 0;
}

8 楼

时间到!

我来回复

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