幸运三角形
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
3
-
描述
-
话说有这么一个图形,只有两种符号组成(‘+’或者‘-’),图形的最上层有n个符号,往下个数依次减一,形成倒置的金字塔形状,除第一层外(第一层为所有可能情况),每层形状都由上层决定,相邻的符号相同,则下层的符号为‘+’,反之,为‘-’;如下图所示(n = 3 时的两种情况):
如果图中的两种符号个数相同,那这个三角形就是幸运三角形,如上图中的图(2).
-
输入
-
有多组测试数据(少于20组)。
每行含一个整数n(0<n<20)。
输出
- 输出相应的幸运三角形个数。 样例输入
-
3 4
样例输出
-
4 6
来源
- 原创 上传者
思路:
这题我没什么思路,数据不是挺大,所以可以敲个TLE代码,浑水摸鱼A过。。。还有就是对于二进制有点不熟练,要多练练才行。。过了这题也要学学优秀代码的方法才行,不然数据再大一点,就过不了了。
打表代码:
#include<iostream> #include<algorithm> #include<cstring> #include<string> #include<cstdio> using namespace std; typedef long long ll; #define CRL(a) memset(a,0,sizeof(a)) #define T 2005 #define inf 0x3f3f3f3f int cnt,a[25],n,bo[25],add,k; bool dp() { for(int j=n-1;j>0;--j) for(int i=0;i<j;++i){ if(bo[i]==bo[i+1])bo[i] = 1,add++; else bo[i]=0; } if(add*2==k)return true; return false; } int solve() { int j; for(int i=0;i<=a[n];++i){ j=i;add=0; for(int t=0;t<n;++t){ if(j&1)bo[t]=1,add++; else bo[t]=0;j>>=1; /*printf("%d",bo[t]);*/ }/*printf("\n");*/ if(dp())cnt++; } return cnt; } void db() { for(int i=0;i<19;++i) a[i+1] = a[i]+(1<<i)/*,printf("%d: %d\n",i+1,a[i+1])*/; } int main() { /*freopen("input.txt","r",stdin);*/ db(); while(~scanf("%d",&n)) { k=(n+1)*n/2;cnt=0; if(k&1){printf("0\n");continue;} printf("%d\n",solve()); } return 0; }
AC代码:
#include<cstdio> using namespace std; int main() { int a[]={0,0,0,4,6,0,0,12,40,0,0,171,410,0,0,1896,5160,0,0,32757}; int n; while(~scanf("%d",&n)){ printf("%d\n",a[n]); } return 0; }
1 2 3 4 。。。。。n
优秀代码的深搜写的非常精妙,从中可以看出这个人的深厚功力。程序用一个t表示第一行中n个数中的第几个数,用第一重循环来赋值n个数的0或1值。然后再用一重循环,不断去更新每行未更新的。因为t不断加1,j每次都是从2开始,所以当t增大,当到j行时,明显j每次只是重复2-t之中,所以这样就实现了当第一行每增加一个数,都能补全为一个三角形了。非常神奇,给他点个赞。
优秀代码:
#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; }
-
有多组测试数据(少于20组)。