描述
话说有这么一个图形,只有两种符号组成(‘+’或者‘-’),图形的最上层有n个符号,往下个数依次减一,形成倒置的金字塔形状,除第一层外(第一层为所有可能情况),每层形状都由上层决定,相邻的符号相同,则下层的符号为‘+’,反之,为‘-’;如下图所示(n = 3 时的两种情况):
如果图中的两种符号个数相同,那这个三角形就是幸运三角形,如上图中的图(2).
- 输入
- 有多组测试数据(少于20组)。
每行含一个整数n(0<n<20)。 - 输出
- 输出相应的幸运三角形个数。
- 样例输入
-
3 4
- 样例输出
-
4 6
///排列组合第一行,然后直接寻找是否相等 #include <iostream> #include <cstdio> #include <cstring> #define N 1010 #define MOD 1000000007 using namespace std; int n,m,ans[25]; int a[25];///待排列的数存储在此 bool vis[15]; int p[N][N],k; int sum,num,tot; void dfs(int cnt)///按字典序输出n个数选m个数的所有排列 { if(cnt==m) { for(int i=0; i<m; i++) { if(ans[i] == ans[i+1] && i+1 < m) p[1][k] = 1,sum++; else p[1][k] = 2; k++; if(ans[i] == 1) sum++; } int c = 2; while(c < m) { k = 0; for(int i = 0; i < m - c + 1; i++) { if(p[c-1][i] == p[c-1][i+1] && i+1 < m - c + 1) p[c][k] = 1,sum++; else p[c][k] = 2; k++; } c++; } if(sum == num) tot++; k = 0; // for(int i=0; i<m; i++) // cout<<ans[i]<<"***"; // cout<<endl; // for(int i = 1; i < m; i++) // { // for(int j = 0 ; j < m-i; j++) // cout<<p[i][j]<<"***"; // cout<<endl; // } // cout<<sum<<" "<<num<<endl; sum = 0; return ; } for(int i=0; i<n; i++) { ans[cnt]=a[i]; dfs(cnt+1); } } int main() { while(cin>>m) { k = 0; n = 2; sum = 0; tot = 0; num = m * (m + 1); if(num % 4) { cout<<0<<endl; continue; } else num /= 4; fill(vis,vis+25,0); a[0] = 1; a[1] = 2; dfs(0); cout<<tot<<endl; } return 0; }
纯粹dfs,回溯还未入门,不过如果应试的话完全可以打表,毕竟数据量不是太大。
///排列组合第一行,然后直接寻找是否相等 #include <iostream> #include <cstdio> #include <cstring> #define N 1010 #define MOD 1000000007 using namespace std; int n,m,ans[25]; int a[25];///待排列的数存储在此 bool vis[15]; int p[N][N],k; int sum,num,tot; void dfs(int cnt)///按字典序输出n个数选m个数的所有排列 { if(cnt==m) { for(int i=0; i<m; i++) { if(ans[i] == ans[i+1] && i+1 < m) p[1][k] = 1,sum++; else p[1][k] = 2; k++; if(ans[i] == 1) sum++; } int c = 2; while(c < m) { k = 0; for(int i = 0; i < m - c + 1; i++) { if(p[c-1][i] == p[c-1][i+1] && i+1 < m - c + 1) p[c][k] = 1,sum++; else p[c][k] = 2; k++; } c++; } if(sum == num) tot++; k = 0; // for(int i=0; i<m; i++) // cout<<ans[i]<<"***"; // cout<<endl; // for(int i = 1; i < m; i++) // { // for(int j = 0 ; j < m-i; j++) // cout<<p[i][j]<<"***"; // cout<<endl; // } // cout<<sum<<" "<<num<<endl; sum = 0; return ; } for(int i=0; i<n; i++) { ans[cnt]=a[i]; dfs(cnt+1); } } int main() { for(m = 1; m < 21; m++) //while(cin>>m) { k = 0; n = 2; sum = 0; tot = 0; num = m * (m + 1); if(num % 4) { cout<<0<<","; continue; } else num /= 4; fill(vis,vis+25,0); a[0] = 1; a[1] = 2; dfs(0); cout<<tot<<","; } return 0; }
回溯才是正解,可以减掉重复计算的值,但是自己没搞懂,留下正解先
///边回溯边计算,避免重复计算 #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) //只取 0('+') 或者 1('-') { 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() { 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 ", sum); } return 0; }
http://www.cnblogs.com/dongsheng/archive/2013/06/16/3138607.html