题目大意:小兔的叔叔从外面旅游回来给她带来了一个礼物,小兔高兴地跑回自己的房间,拆开一看是一个棋盘,小兔有所失望。不过没过几天发现了棋盘的好玩之处。从起点(0,0)走到终点(n,n)的最短路径数是C(2n,n),现在小兔又想如果不穿越对角线(但可接触对角线上的格点),这样的路径数有多少? 解题思路:很明显的DP,dp[i][j]表示走到(i,j)的路径数。 转移方程:dp[i][j]=dp[i-1][j]+dp[i][j-1](i!=j); dp[i][j]=0(i=j); 这里面要注意的是这里的(0,0)表示的是格子,而方程里面的(i,j)表示的是下格点 所以事实上(n,n)换成格子表示是(n+1,n+1) 而所有的对角线上的格点也是来源于其左边和上面的格点所以ans=dp[n+1][n]+dp[n][n+1] 代码:
1#include <iostream> 2#include <cstdio> 3#include <cstring> 4#include <cmath> 5 6using namespace std; 7 8int m,n,k; 9long long dp[40][40]; 10 11int main() 12{ dp[0][0]=0; 13 for (int i=0; i<=37; i++) 14 { dp[0][i]=1; dp[i][0]=1; 15 } 16 for(int i=1; i<=37; i++) 17 for(int j=1; j<=37; j++) 18 if(i != j) 19 dp[i][j] = dp[i-1][j] + dp[i][j-1]; 20 21 else 22 dp[i][j] = 0; 23 k=1; 24 while(cin >> n) 25 {if (n==-1) break; 26 cout <<k <<" "<<n<< " " <<dp[n+1][n]+dp[n][n+1] << endl; k++;} 27 28 return 0; 29} 30 其实勒,这道题是由于数据量比较小,所以可以使用DP+long long来解决,但是其本质上还是属于一个排列组合问题,如果数据量变大的话,需要用到大数来解决。
题目大意:给你n个不同的节点,求可以构成多少种二叉树。 解题思路:1)n个节点构成多少种二叉树的问题显然是卡特兰数问题。 递推式:Cn=Cn-1*[(4n-2)/(n+1)] 通项式:Cn=1/(n-1)*C(n-2,2n-4) 2)注意,是n个不同的点,所以点变换顺序形成的二叉树不同故:SUM=Cn*n! 修改了1130的代码...
1#include <iostream> 2#include <cstdio> 3#include <algorithm> 4#include <cstring> 5 6using namespace std; 7#define MAX 105 8#define BASE 10000 9typedef int myType[MAX+10]; 10void multiply ( int a[], int Max, int b ) //大数乘小数 11{ int i,array=0; 12 for (i=Max-1; i>=0; i--) 13 { 14 array+=b*a[i]; 15 a[i] = array%BASE; 16 array /= BASE; 17 } 18} 19void divide ( int a[], int Max, int b ) //大数除小数 20{ 21 int i,div=0; 22 for (i=0;i<Max; i++) 23 { 24 div = div*BASE + a[i]; 25 a[i] = div / b; 26 div %= b; 27 } 28} 29void outPut ( myType ctl[MAX] ,int N ) 30{ 31 int i = 0; 32 while ( i < MAX && ctl[N][i] == 0 ) 33 { 34 i ++ ; //去前导0 35 } 36 cout << ctl[N][i++]; 37 while ( i < MAX ) 38 { 39 40 printf ( "%04d", ctl[N][i++] ); 41 } 42 cout << endl; 43} 44void setNum ( myType ctl[MAX] ) 45{ 46 memset ( ctl[1], 0, MAX * sizeof ( int ) ); 47 ctl[1][MAX-1] = 1; 48 for ( int i = 2; i < 101; i ++ ) 49 { 50 memcpy ( ctl[i], ctl[i-1], MAX * sizeof ( int ) ); 51 multiply ( ctl[i], MAX, 4 * i - 2 ); 52 divide ( ctl[i], MAX, i + 1 ); 53 } 54} 55myType ctl[MAX]; 56int main() 57{ 58 setNum ( ctl ); 59 int N; 60 while ( cin >> N ) { if (N==0) break; 61 else 62 {for (int p=1; p<=N; p++) multiply ( ctl[N], MAX, p ); 63 outPut ( ctl, N ); } 64 } 65 return 0; 66} 67
题目大意:给出一棵n节点的二叉树,求其组成的总数。 解题思路:典型的卡特兰数裸的题目,详见: http://baike.baidu.com/view/2499752.htm 公式:Cn=1/(n-1)*C(n-2,2n-4); 由于是大数的卡特兰数,涉及到一个计算问题,比较麻烦。 不过由于以前在其他地方应用过,有MiYu的大数版卡特兰数模版,就直接套用了。 我找不到原来的地址了,不过有别人转载的文章: http://blog.csdn.net/geniusluzh/article/details/5860975 这里的代码的MiYu的代码,仅供参考。
1#include <iostream> 2#include <cstdio> 3#include <algorithm> 4#include <cstring> 5 6using namespace std; 7#define MAX 105 8#define BASE 10000 9typedef int myType[MAX+10]; 10void multiply ( int a[], int Max, int b ) //大数乘小数 11{ int i,array=0; 12 for (i=Max-1; i>=0; i--) 13 { 14 array+=b*a[i]; 15 a[i] = array%BASE; 16 array /= BASE; 17 } 18} 19void divide ( int a[], int Max, int b ) //大数除小数 20{ 21 int i,div=0; 22 for (i=0;i<Max; i++) 23 { 24 div = div*BASE + a[i]; 25 a[i] = div / b; 26 div %= b; 27 } 28} 29void outPut ( myType ctl[MAX] ,int N ) 30{ 31 int i = 0; 32 while ( i < MAX && ctl[N][i] == 0 ) 33 { 34 i ++ ; //去前导0 35 } 36 cout << ctl[N][i++]; 37 while ( i < MAX ) 38 { 39 40 printf ( "%04d", ctl[N][i++] ); 41 } 42 cout << endl; 43} 44void setNum ( myType ctl[MAX] ) 45{ 46 memset ( ctl[1], 0, MAX * sizeof ( int ) ); 47 ctl[1][MAX-1] = 1; 48 for ( int i = 2; i < 101; i ++ ) 49 { 50 memcpy ( ctl[i], ctl[i-1], MAX * sizeof ( int ) ); 51 multiply ( ctl[i], MAX, 4 * i - 2 ); 52 divide ( ctl[i], MAX, i + 1 ); 53 } 54} 55myType ctl[MAX]; 56int main() 57{ 58 setNum ( ctl ); 59 int N; 60 while ( cin >> N ) // 这里根据各题要求需要做相应变化 61 { outPut ( ctl, N ); } 62 return 0; 63} 64
今天,去HDOJ上的ACM steps上切题了,切的好辛苦..... 大部分的题目并不难,这凸显了自己的代码能力很不过关,需要写多点题,努力提高代码的稳定性。 明天,后天是SCAU暑假培训的最后两场个人赛了,....,在保的前提下要力争把排位冲前点,主要是 心态,一定要放平稳要调整好。 希望八月份的组队赛能够有更好的进步,我们希望我们能够完成自己的目标。 By SCAU_3_idiots' wyh
题目大意:给出n个房间,打开房间门的办法有撞击和用钥匙打开,编号1的门不能撞击。已知每个房间里有n间房间中某间房子的钥匙,问在k次撞击之内,求把房间门全部打开的概率。 解题思路:1)第一扇门必须撞开。 2)当钥匙无法打开关闭的门的时候,必须继续采取撞开的方式 3)编号1的门不能撞击。 3)到这里,题目演变成了求在n间房间中形成少于k个环的概率(编号1的门不能独立成环)。 .................然后,我就不会做了。接着上网百度了一下就n个元素划分成k个环的方法~~,.....第一次接触了所谓的第一类斯特林数。 斯特林数学习资料: http://www.mathchina.com/usr1PvjRWKew/5/2/CBB9CCD8C1D6CAFD_1178220836.bmp 或者: /Files/wyh123/CBB9CCD8C1D6CAFD_1178220877.doc 继续思路: 4)在这里我们很容易得出n把钥匙的排列数是n!,只要我们求出所有可能的方案数,则概率p=sum/n! 5)形成少于k个环的总数有s(n,k)+s(n,k-1)+.......+s(n,1) 6)由于编号1的房间不能独立成环,所以要计算出编号1房间独立成环的成功方案数:s(n-1,k-1)+s(n-1,k-2)+.....s(n-1,2)+s(n-1,1) 7)总方案就为:sum=s(n,k)+s(n,k-1)+.....+s(n,1)-(s(n-1,k-1)+s(n-1,k-2)+.....s(n-1,2)+s(n-1,1)) 到这里问题解决。发现自己的数学基础还是不行啊,仍需加油,补充!!!
1#include <iostream> 2#include <cstring> 3#include <cstdlib> 4#include <cmath> 5#include <cstdio> 6#include <algorithm> 7 8using namespace std; 9 10long long f[30]; 11long long s[30][30]; 12int i,k,n,T; 13double sum; 14 15void init() 16{ 17 int i,j; 18 f[1]=1; 19 for(i=2;i<30;i++) 20 f[i]=i*f[i-1]; 21 for(i=0;i<30;i++) 22 s[i][0]=0; 23 s[1][1]=1; 24 for(i=2;i<30;i++) 25 { 26 for(j=1;j<=i;j++) 27 s[i][j]=s[i-1][j-1]+(i-1)*s[i-1][j]; 28 } 29} 30 31 32int main() 33{ scanf("%d",&T); 34 init(); 35 while(T--) 36 { 37 scanf("%d%d",&n,&k); 38 sum=0; 39 for(i=1;i<=k;i++) 40 sum=sum+s[n][i]-s[n-1][i-1]; 41 sum=1.0*sum/f[n]; 42 printf("%.4lf\n",sum); 43 } 44 return 0; 45} 46
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|
常用链接
留言簿
随笔分类
随笔档案
文章分类
文章档案
搜索
最新评论
阅读排行榜
评论排行榜
|
|