NYOJ491幸运三角形

来源:互联网 发布:2017天天采集软件 编辑:程序博客网 时间:2024/05/19 23:19


幸运三角形

时间限制:1000 ms  |  内存限制:65535 KB
难度:3
描述

        话说有这么一个图形,只有两种符号组成(‘+’或者‘-’),图形的最上层有n个符号,往下个数依次减一,形成倒置的金字塔形状,除第一层外(第一层为所有可能情况),每层形状都由上层决定,相邻的符号相同,则下层的符号为‘+’,反之,为‘-’;如下图所示(n = 3 时的两种情况):

                                           

如果图中的两种符号个数相同,那这个三角形就是幸运三角形,如上图中的图(2).

输入
有多组测试数据(少于20组)。
每行含一个整数n(0<n<20)。
输出
输出相应的幸运三角形个数。
样例输入
34
样例输出
46
/*#include <stdio.h> #include <stdlib.h> #include <string.h> int n, cnt; int a[25]; int check()//每次总是觉得这个check函数是最难得 {     int i, j, t1, t0;     t1 = 0;     t0 = 0;     for(j = n - 1; j >= 0; j--)//外层循环是有几层,即循环的n次     {         for(i = 0; i <= j; i++)//里层循环式一层有几个字符,即有j个         {             if(a[i] == 1)//计数是+还是-                 t1++;             else                 t0++;             if(i > 0)//因为是用的一维数组存的,所以这里的主要作用是把这个一维数组变成下一层所需要的样式             {                 if(a[i] == a[i - 1])//符号相同则是+                     a[i - 1] = 1;                 else//否则是-                     a[i - 1] = 0;             }         }     }     if(t1 == t0)         return 1;     return 0; } void dfs(int x) {     if(x == n)     {         if(check() == 1)             cnt++;         return ;//开始把return放在if里面了一直出不来结果,真是笨笨的脑袋     }     a[x] = 1;//这里并没有往常一样有if判断了,而是直接深搜了     dfs(x + 1);     a[x] = 0;//这里回溯回来的时候继续深搜下去,思路还是比较清晰的     dfs(x + 1); } int main() {     while(scanf("%d", &n) != EOF)     {         cnt = 0;         dfs(0);         printf("%d\n", cnt);     }     return 0; } */  打表#include <stdio.h>  int a[21] = {0,0,0,4,6,0,0,12,40,0,0,171,410,0,0,1896,5160,0,0,32757};//打表最好不要用for循环  int main()  {      int n;      while(scanf("%d", &n) != EOF)      {          printf("%d\n", a[n]);      }      return 0;  }  

OJ平台最优代码:

 #include"iostream"  #include<cstring>  #include<stdio.h>  #include<time.h>  using namespace std;  typedef unsigned char uchar;    char cc[2]={'+','-'};   //便于输出  int n,                  //第一行符号总数      half,               //全部符号总数一半      counter;            //1计数,即“-”号计数        char **p;               //符号存储空间      long sum;               //符合条件的三角形计数    //t,第一行第t个符号  void Backtrace(int t)  {      int i, j;            if( t > n )          sum++;      else         for(i=0; i<2; ++i)         {              p[1][t] = i;//第一行第t个符号              counter += i;       //“-”号统计              for(j=2; j<=t; ++j)  //当第一行符号>=2时,可以运算出下面行的某些符号              {                  p[j][t-j+1] = p[j-1][t-j+1]^p[j-1][t-j+2];//通过异或运算下行符号                  counter += p[j][t-j+1];                                   }              if( (counter <= half) && ( t*(t+1)/2 - counter <= half) )//若符号统计未超过半数,并且另一种符号也未超过半数                  Backtrace(t+1);         //在第一行增加下一个符号                 //回溯,判断另一种符号情况              for(j=2; j<=t; ++j)                    counter -= p[j][t-j+1];                    counter -= i;         }  }    int main()  {        freopen("input.txt","r",stdin);      while(scanf("%d", &n) != EOF)      {      counter = 0;      sum = 0;      half = n*(n+1)/2;            if( half%2 == 0 )      {//总数须为偶数,若为奇数则无解          half /= 2;          p = new char *[n+1];          for(int i=0; i<=n; ++i)          {             p[i] = new char[n+1];             memset(p[i], 0, sizeof(char)*(n+1));          }             Backtrace(1);      }         printf("%d\n", sum);}      return 0;  }          

程序用一个t表示第一行中n个数中的第几个数,用第一重循环来赋值n个数的0或1值。然后再用一重循环,不断去更新每行未更新的。因为t不断加1,j每次都是从2开始,所以当t增大,当到j行时,明显j每次只是重复2-t之中,所以这样就实现了当第一行每增加一个数,都能补全为一个三角形了。