C语言程序设计100例之(50):向下的路径
例50 向下的路径
问题描述
有一个size=N的图,如图1所示。然后我们将找到一条从顶部节点到底部节点的向下路径。
首先,我们选择顶部节点作为开始。然后在任何节点,我们都可以沿着蓝色边缘水平或向下移动,到达下一个节点。当我们到达其中一个底部节点时,移动结束。然后,我们可以得到从顶部节点到底部节点的向下路径。请注意,在移动过程中,每条蓝边最多走过1次。
例如,size=2时,图2中的黄色路径显示了8条向下的路径。
您的任务是计算存在多少向下的路径。
输入
第一行中有一个整数T(1<=T<=1000),表示总共有T个测试用例。
对于每个测试用例,只有一个整数N(1<=N<=10^18)表示图形的大小。
输出
对于每个测试用例,在一行中输出上述任务的正确答案。
因为答案可能非常大,只输出它除以1000003的余数即可。
输入样例
输出样例
(1)编程思路。
设a[i]表示size=i时从顶部节点到底部节点的向下路径的条数。
a[1]=2=1+1
a[2]=8=2*2*a[1]
a[3]=48=3*2*a[2]=3*2*8 (size=3时,可以先从顶部节点移动到最底行的上一行,此时方法数为a[2],其结束点一定在上一行的3个节点之一,这3个节点,每个结点均有两种方法向下移动到底行,故a[3]=3*2*a[2])
......
a[n]= 2*n*a[n-1]
即:a[n]=2^n*n!
因为a[n]=2^n*n!,所以当n>1000003时,n!中有1000003这个因数,故ans=0。
(2)源程序。
#include
#define MAXN 1000003
long long a[MAXN];
int main()
{
a[0]=0; a[1]=2;
int i;
for (i=2;i a[i]=(a[i-1]*2*i)%MAXN; } int t; scanf("%d",&t); while(t--){ long long n; scanf("%lld",&n); if (n<=MAXN) printf("%lld\n",a[n%MAXN]); else printf("0\n"); } return 0; } 本题选自洛谷题库 (https://www.luogu.org/problem/P2807) 题目描述 把大三角形的每条边n等分,将对应的等分点连接起来(连接线分别平行于三条边),这样一共会有多少三角形呢?编程来解决这个问题。 输入格式 第一行为整数t(≤100),表示测试数据组数;接下来t行,每行一个正整数n(≤500)。 输出格式 对于每个n,输出一个正整数,表示三角形个数。 输入样例 输出样例 13 (1)编程思路。 设a[i]表示边长为i的三角形个数。 先用下图所示的边长为4的三角形来列举边长n<=4的三角形个数。 显然,a[1]=1。 当i=2时,对应图中上两行。边长为1的小三角形有4个,其中3个顶点向上(红色三角形),1个顶点向下(白色三角形);边长为2的三角形有1个。所以,a[2]=5。 当i=3时,对应图中上三行。可以看成是在上两行(i=2)的基础上增加第3行扩展而来。此时,增加了边长为1的小三角形有5个,其中3个顶点向上(红色三角形),2个顶点向下(白色三角形);增加了边长为2的三角形有2个,顶点均向上;增加了边长为3的三角形1个,顶点向上。所以,a[3]=a[2]+5+2+1=13。 当i=4时,对应图中全部四行。可以看成是在上面三行(i=3)的基础上增加第4行扩展而来。此时,增加了边长为1的小三角形有7个,其中4个顶点向上(红色三角形),3个顶点向下(白色三角形);增加了边长为2的三角形有4个,其中3个顶点向上,1个顶点向下;增加了边长为3的三角形2个,顶点均向上;增加了边长为4的三角形1个,顶点向上。所以,a[4]=a[3]+7+4+2+1=27。 更一般地,i=n时,可以看成是在上n-1行(i=n-1)的基础上增加第n行而来。此时,可分两种情况讨论: 1)增加的顶点向上的三角形中,边长为1的,增加了n个,边长为2的,增加了n-1个,…,边长为n-1的,增加了2个,边长为n的,增加了1个。共增加了n+(n-1)+…+2+1=(n+1)*n/2个。 2)增加的顶点向下的三角形中,又按n的奇偶不同分开讨论。当n为偶数时,边长为1的,增加了n-1个,边长为2的,增加了n-3个,…,边长为n/2-1的,增加了2个,边长为n/2的,增加了1个,共增加了(n-1+1)*(n/2) / 2=n*n/4个;当n为奇数时,边长为1的,增加了n-1个,边长为2的,增加了n-3个,…,边长为(n-1)/2的,增加了2个,边长为(n+1)/2的,增加了0个,共增加了((n-1+2)*(n-1)/2) / 2=(n+1)*(n-1)/4个。 由此得到,若n为偶数,a[n]=a[n-1]+(n+1) * n / 2 + n * n /4 若n为奇数,a[n]=a[n-1] + (n + 1 ) * n / 2 + (n+1) * (n-1) / 4 (2)源程序。 #include int main() { int a[501]={0,1}; int i; for (i=2;i<=500;i++) { if(i%2==0) a[i]=a[i-1]+(1+i)*i/2+i*i/4; else a[i]=a[i-1]+(1+i)*(i-1)/4+(1+i)*i/2; } int t,n; scanf("%d",&t); for (i = 1;i <= t;i++) { scanf("%d",&n); printf("%d\n",a[n]); } return 0; } 问题描述 给定一个正整数n,请求出n位二进制数中,确定不包含相邻1的n位序列的个数。例如,对于n=3,答案为5(序列000、001、010、100、101符合要求,而011、110、111不符合要求)。 输入 第1行给出测试用例的数量T。 对于每个测试用例,在一行中给出一个小于45的正整数n。 输出 每个测试用例的输出都以一行开头,其中包含“Scenario #i:”,其中i是从1开始的用例编号。然后打印一行,其中包含没有相邻1的n位序列数。 输入样例 输出样例 Scenario #1: Scenario #2: (1)编程思路。 设a[i]表示不包含相邻1的i位二进制数序列的个数。由于1不能连续,那么长度为n的二进制数,第1位是1,则第2位只能为0,情况总数等于a[n-2],第1位是0,则情况总数等于a[n-1],因此,a[n]=a[n-1]+a[n-2]。 (2)源程序。 #include int main() { long long a[50]; a[1] = 2; a[2] = 3; int i; for (i=3; i<=45; i++) { a[i]=a[i-1]+a[i-2]; } int t,n; scanf("%d",&t); for (i=1;i<=t;i++) { scanf("%d",&n); printf("Scenario #%d:\n",i); printf("%lld\n\n",a[n]); } return 0; } 问题描述 马在一个n行m列棋盘的左下角(1,1)的位置,它想要走到终点右上角(n,m)的位置。而众所周知,马是要走日子格的。但现在这匹马不想走回头路——也就是说,它只会朝向上的方向跳,不会朝向下的方向跳。 这匹马想从起点跳到终点,一共有多少种走法呢? 输入格式 第一行两个数n,m(n<=100,m<=100),表示一个n行m列的棋盘,马最初是在左下角(1,1)的位置,终点在右上角(n,m)的位置。 输出格式 输出有一行,一个数表示走法数。由于答案可能很大,所以输出答案除以1000000007所得的余数即可。 输入样例 4 4 输出样例 (1)编程思路。 设F[i] [j] 表示马从左下角(1,1)跳到(i,j)的走法种数。 由于只能往上跳,即跳动过程中,行i只能增大,因此第1行中的各位置是怎么也跳不上去,即F[1][j]=0(1<=j<=m)。又因为刚开始就在(1,1)这个位置上,从(1,1)往上只能跳两个点(2,3)和(3,2),即F[2][3]=F[3][2]=1。. 由于位置(i,j),只能从(i-1,j-2),(i-2,j-1),(i-2,j+1),(i-1,j+2)这四个点跳过来,因此有 F[i][j]= F[i-1][j-2]+F[i-2][j-1]+F[i-2][j+1]+F[i-1][j+2] 需要注意的是,由于棋盘是有边界的,因此在计算时,对每个点判断一下,如果满足条件就加上,否则不加。例如,若i-1>1 && j-2>=1,F[i-1][j-2]就可以加上;若i-1>1 && j+2<=m,F[i-1][j+2]就可以加上。 (2)源程序。 #include int main() { int f[105][105]={0}; int n,m; scanf("%d%d",&n,&m); f[2][3]=f[3][2]=1; int i,j; for (i=1; i<=n; i++) { for (j=1; j<=m; j++) { if (i==1) f[i][j] = 0; if (i-2>1 && j+1<=m) f[i][j] = (f[i][j]+f[i-2][j+1])%1000000007; if (i-1>1 && j+2<=m) f[i][j] = (f[i][j]+f[i-1][j+2])%1000000007; if (i-1>1 && j-2>=1) f[i][j] = (f[i][j]+f[i-1][j-2])%1000000007; if (i-2>1 && j-1>=1) f[i][j] = (f[i][j]+f[i-2][j-1])%1000000007; } } printf("%d\n",f[n][m]); return 0; }习题50
50-1 三角形计数
50-2 1和1不相邻
50-3 跳马