hdu 2510 符号三角形

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2510

 

题目描述:

 

Problem Description

符号三角形的 第1行有n个由“+”和”-“组成的符号 ,以后每行符号比上行少1个,2个同号下面是”+“,2个异 号下面是”-“ 。计算有多少个不同的符号三角形,使其所含”+“ 和”-“ 的个数相同 。 n=7时的1个符号三角形如下:
+ + - + - + + 
+ - - - - + 
- + + + - 
- + + - 
- + - 
- - 
+

 

 

Input

每行1个正整数n <=24,n=0退出.

 

 

Output

n和符号三角形的个数. 

 

 

Sample Input

 

15 16 19 20 0

 

 

Sample Output

 

15 1896 16 5160 19 32757 20 59984

 

 

 

题目分析:

dfs,易知每一个符号三角形都是由第一行所决定,当第一行确定了下来以后那么后面的n-1行也就由题目中的规则唯一的确定了下来,这个道理相信许多人都知道,关键是如何去实现它,在这里我也困扰了许久,最后突然想到我们也可以通过倒着做,即先确定最后一行的哪一个数,这里只要考虑两种情况,要么是‘+’要么是'-',然后呢,我们再推出他的上面一行,同样,由于下面一行已经确定了,所以在这里我们只要知道这一行的第一个符号是什么,那么这一行的所有符号也就唯一确定了下来,在这里我们也就只需要考虑两种情况,要么'+'要么'-',所以也就是说,每一行都只要考虑第一个符号,大大的减少复杂性

 

第一发深搜超时,用的打表暴力AC:

 

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long

/*const int maxn=25;
int n;
ll anss;
int map[maxn][maxn];
ll ans[maxn];

void dfs(int m,int z,int f)//把数字三角形倒过来看,一共就两种
{
    if(z>(n*(n+1)/4)||f>(n*(n+1)/4))
        return;
    if(m==n+1)
    {
        if(z==f)
        {
            anss++;
        }
        return;
    }

    if(m==1)
    {
        map[1][1]=1;
        dfs(m+1,z+1,f);
        map[1][1]=0;
        dfs(m+1,z,f+1);
    }
    else
    {
        int num_neg=0,num_pos=0;
        //首位是0
        //1是+,0是-
        map[m][1]=0;
        num_neg++;
        for(int i=2;i<=m;i++)
        {
            if(map[m-1][i-1]==1)
            {
                map[m][i]=map[m][i-1];
                if(map[m][i])
                    num_pos++;
                else
                    num_neg++;
            }
            else
            {
                if(map[m][i-1]==1)
                {
                    map[m][i]=0;
                    num_neg++;
                }
                else
                {
                    map[m][i]=1;
                    num_pos++;
                }
            }
        }
        dfs(m+1,z+num_pos,f+num_neg);

        //首位是1
        num_pos=0;
        num_neg=0;
        map[m][1]=1;
        num_pos++;
        for(int i=2;i<=m;i++)
        {
            if(map[m-1][i-1])
            {
                map[m][i]=map[m][i-1];
                if(map[m][i])
                    num_pos++;
                else
                    num_neg++;
            }
            else
            {
                if(map[m][i-1])
                {
                    map[m][i]=0;
                    num_neg++;
                }
                else
                {
                    map[m][i]=1;
                    num_pos++;
                }
            }
        }
        dfs(m+1,z+num_pos,f+num_neg);
    }
}*/

int main()
{
    /*for(int i=1;i<=24;i++)
    {
        n=i;
        anss=0;
        memset(map,0,sizeof(map));
        dfs(1,0,0);
        ans[i]=anss;
        printf("%d ",anss);
    }*/
    ll v[]={0,0,0,4,6,0,0,12,40,0,0,171,410,0,0,1896,5160,0,0,32757,59984,0,0,431095,822229};
    while(scanf("%d",&n)!=0&&n!=0)
    {
        //memset(map,0,sizeof(map));
        //dfs(1,0,0);
        printf("%d %lld\n",n,v[n]);
    }
    return 0;
}

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值