给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。
对于给定的由n行数字组成的数字三角形,计算从三角形的顶至底的路径经过的数字和的最大值。
数字三角形问题
输入格式:
输入数据的第1行是数字三角形的行数n,1≤n≤100。接下来n行是数字三角形各行中的数字。所有数字在0..99之间。
输出格式:
输出数据只有一个整数,表示计算出的最大值。
输入样例:
在这里给出一组输入。例如:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出样例:
30
#include <stdio.h>
#include <stdlib.h>
int n,a[100][100]={0};
int main()
{
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
scanf("%d",&a[i][j]);
}
}
for(i=n-1;i>=1;i--)
{
for(j=1;j<=i;j++)
{
a[i][j]=a[i+1][j]>a[i+1][j+1]?a[i][j]+a[i+1][j]:a[i][j]+a[i+1][j+1];
}
}
printf("%d",a[1][1]);
return 0;
}
马上就要放假了,小鑫打算去爬山。
小鑫要去爬的这座山有n个海拔区间。为了清楚描述我们可以从上到下标号1到n。
第i个区间有i个落脚点,每一个落脚点都有一个危险值。
小鑫需要在第n个海拔区间挑选一个点向上爬,爬到第1个海拔区间(也就是山顶)。他必须规划一条路径,让危险值之和最小。这样才安全的。
并不是任意两个落脚点之间都可以相互到达。我们这样定义对于第i个(i<n)区间的第j个落脚点,只有第i+1个区间的第j个和第j+1个可以到达。
你能帮助他找到最安全的路么?
小鑫去爬山
输入格式:
输入数据为多组,到文件结束。
对于每一组数据,第一行有一个数,为n 。n≤100;
接下来有n行,第i行有i个数。代表第i个区间i个落脚点的危险值。
所有数据均在int范围内。
输出格式:
对于每组数据,输出一行一个数,为答案。
#include <stdio.h>
#include <stdlib.h>
int n,a[105][105]={0};
int main()
{
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
scanf("%d",&a[i][j]);
}
}
for(i=n-1;i>=1;i--)
{
for(j=1;j<=i;j++)
{
a[i][j]=a[i+1][j]<a[i+1][j+1]?a[i][j]+a[i+1][j]:a[i][j]+a[i+1][j+1];
}
}
printf("%d",a[1][1]);
return 0;
}
给定两个序列 X={x1,x2,…,xm} 和 Y={y1,y2,…,yn},找出X和Y的最长公共子序列。
最长公共子序列问题
输入格式:
输入数据有多组,每组有两行 ,每行为一个长度不超过500的字符串(输入全是大写英文字母(A,Z)),表示序列X和Y。
输出格式:
每组输出一行,表示所求得的最长公共子序列的长度,若不存在公共子序列,则输出0。
输入样例:
ABCBDAB
BDCABA
输出样例:
4
#include <stdio.h>
#include <string.h>
int main()
{
char x[505],y[505];
int m,n,i,j;
while(gets(x)&&gets(y))
{
int a[505][505]={0};
m=strlen(x);
n=strlen(y);
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(x[i]==y[j])
{
a[i+1][j+1]=a[i][j]+1;
}
else
{
a[i+1][j+1]=a[i][j+1]>a[i+1][j]?a[i][j+1]:a[i+1][j];
}
}
}
printf("%d",a[m][n]);
}
return 0;
}
从一个给定的串中删去(不一定连续地删去)0个或0个以上的字符,剩下地字符按原来顺序组成的串。例如:“ ”,“a”,“xb”,“aaa”,“bbb”,“xabb”,“xaaabbb”都是串“xaaabbb”的子序列。(例子中的串不包含引号。)
编程求N个非空串的最长公共子序列的长度。限制:2<=N<=100;N个串中的字符只会是数字0,1,…,9或小写英文字母a,b,…,z;每个串非空且最多含100个字符;N个串的长度的乘积不会超过30000。
最长公共子序列
输入格式:
文件第1行是一个整数T,表示测试数据的个数(1<=T<=10)。接下来有T组测试数据。各组测试数据的第1行是一个整数Ni,表示第i组数据中串的个数。各组测试数据的第2到N+1行中,每行一个串,串中不会有空格,但行首和行末可能有空格,这些空格当然不算作串的一部分。
输出格式:
输出T行,每行一个数,第i行的数表示第i组测试数据中Ni个非空串的最长公共子序列的长度。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char s[105][105];
int len[105];
int dp[30005];
int n;
int max2(int a,int b)
{
return (a>b?a:b);
}
int recur(int *x)
{
int index,i,j,ret;
//如果当前有字符串的长度为0,则返回0
for(i=1;i<=n;i++)
if(x[i]==0)
return 0;
//逆序建立映射
index=x[n]-1;
for(i=n-1;i>=1;i--)
index=index*len[i]+x[i]-1;
//记忆化搜索
if(dp[index]>=0)
return dp[index];
//判断是否所有串的最后一个字符都相等
for(i=2;i<=n;i++)
if(s[1][x[1]-1]!=s[i][x[i]-1])
break;
if(i>n) //如果都相等,则最大长度+1
{
for(j=1;j<=n;j++)
x[j]--;
ret=recur(x)+1;
for(j=1;j<=n;j++)
x[j]++;
}
else //否则,求删去某个字符串的最后一个字符之后得到的最大值
{
ret=0;
for(j=1;j<=n;j++)
{
x[j]--;
int t=recur(x);
ret=max2(t,ret);
x[j]++;
}
}
dp[index]=ret;
return ret;
}
int main()
{
int t,i;
int temp[105];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s",s[i]);
len[i]=temp[i]=strlen(s[i]);
}
memset(dp,-1,sizeof(dp));
printf("%d\n",recur(temp));
}
return 0;
}
一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1<= i1 < i2 < ... < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8)。
你的任务,就是对于给定的序列,求出最长上升子序列的长度。
最长上升子序列
输入格式:
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。
输出格式:
最长上升子序列的长度。
#include<stdio.h>
#include<stdlib.h>
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
int a[1004], dp[1004];
int main()
{
int N;
int ans = -1;
scanf("%d", &N);
for(int i = 1; i <= N; i++)
{
scanf("%d", &a[i]);
dp[i] = 1;
}
for(int i = 1; i <= N; i++)
{
for(int j = 1; j < i; j++)
{
if(a[j] < a[i])
{
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
for(int i = 1; i <= N; i++)
ans = max(ans, dp[i]);
printf("%d\n", ans);
return 0;
}
一个只包含非负整数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列{a1, a2, ...,aN},我们可以得到一些上升的子序列{ai1, ai2, ..., aiK},这里1 ≤ i1 < i2 <...< iK ≤ N。例如:对于序列{1, 7, 3, 5, 9, 4, 8},有它的一些上升子序列,如{1, 7}, {3, 4, 8}等等。这些子序列中序列和最大的是子序列{1, 3, 5, 9},它的所有元素的和为18。
对于给定的一个序列,求出它的最大的上升子序列的和。
注意:最长的上升子序列的和不一定是最大的哦。
上升子序列
输入格式:
输入包含多组测试数据,对于每组测试数据:
输入数据的第一行为序列的长度 n(1 ≤ n ≤ 1000),
第二行为n个非负整数 b1,b2,...,bn(0 ≤ bi ≤ 1000)。
输出格式:
对于每组测试数据,输出其最大上升子序列的和。
#include <stdio.h>
#include <stdlib.h>
int max(int a,int b)
{
return a>b?a:b;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
int i,j;
int a[1004],b[1004];
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
for(i=1;i<=n;i++)
{
for(j=1;j<i;j++)
{
if(a[j]<a[i]&&a[i]+b[j]>b[i])
{
b[i]=a[i]+b[j];
}
}
}
int sum=a[1];
for(i=1;i<=n;i++)
sum=max(sum,b[i]);
printf("%d\n",sum);
}
return 0;
}
给定一个函数 f(a, b, c):
如果 a ≤ 0 或 b ≤ 0 或 c ≤ 0 返回值为 1;
如果 a > 20 或 b > 20 或 c > 20 返回值为 f(20, 20, 20);
如果 a < b 并且 b < c 返回 f(a, b, c−1) + f(a, b−1, c−1) − f(a, b−1, c);
其它情况返回 f(a−1, b, c) + f(a−1, b−1, c) + f(a−1, b, c−1) − f(a-1, b-1, c-1)。
看起来简单的一个函数?你能做对吗?
递归的函数
输入格式:
输入包含多组测试数据,对于每组测试数据:
输入只有一行为 3 个整数a, b, c(a, b, c < 30)。
输出格式:
对于每组测试数据,输出函数的计算结果。
#include <stdio.h>
#include <stdlib.h>
long long fun[35][35][35]={0};
int f(int a,int b,int c)
{
if(a<=0||b<=0||c<=0)
return 1;
if(fun[a][b][c]!=0)
{
return fun[a][b][c];
}
else if(a>20||b>20||c>20)
{
return f(20,20,20);
}
else if(a<b&&b<c)
{
return fun[a][b][c]=f(a,b,c-1)+f(a,b-1,c-1)-f(a,b-1,c);
}
else
{
return fun[a][b][c]=f(a-1,b,c) + f(a-1,b-1,c) + f(a-1,b,c-1)-f(a-1,b-1,c-1);
}
}
int main()
{
int a,b,c;
while(~scanf("%d%d%d",&a,&b,&c))
{
long long s=f(a,b,c);
printf("%lld\n",s);
}
return 0;
}
有一个mn格的迷宫(表示有m行、n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,输入这mn个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用-1表示无路)。
走迷宫
输入格式:
第一行是两个数m,n(1< m, n< 15),接下来是m行n列由1和0组成的数据,最后两行是起始点和结束点。
输出格式:
所有可行的路径,输出时按照左上右下的顺序。描述一个点时用(x,y)的形式,除开始点外,其他的都要用“->”表示。如果没有一条可行的路则输出-1。
输入样例:
在这里给出一组输入。例如:
5 4
1 1 0 0
1 1 1 1
0 1 1 0
1 1 0 1
1 1 1 1
1 1
5 4
输出样例:
在这里给出相应的输出。例如:
(1,1)->(1,2)->(2,2)->(2,3)->(3,3)->(3,2)->(4,2)->(4,1)->(5,1)->(5,2)->(5,3)->(5,4)
(1,1)->(1,2)->(2,2)->(2,3)->(3,3)->(3,2)->(4,2)->(5,2)->(5,3)->(5,4)
(1,1)->(1,2)->(2,2)->(3,2)->(4,2)->(4,1)->(5,1)->(5,2)->(5,3)->(5,4)
(1,1)->(1,2)->(2,2)->(3,2)->(4,2)->(5,2)->(5,3)->(5,4)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,2)->(4,2)->(4,1)->(5,1)->(5,2)->(5,3)->(5,4)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,2)->(4,2)->(5,2)->(5,3)->(5,4)
(1,1)->(2,1)->(2,2)->(3,2)->(4,2)->(4,1)->(5,1)->(5,2)->(5,3)->(5,4)
(1,1)->(2,1)->(2,2)->(3,2)->(4,2)->(5,2)->(5,3)->(5,4)
#include<stdio.h>
#include<stdlib.h>
struct node
{
int x,y;
}ls[400];
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int vis[20][20],mp[20][20];
int n,m,step,f,ex,ey;
void dfs(int x1,int y1)
{
if(x1==ex&&y1==ey)
{
f=1;
for(int i=0;i<step;i++)
{
printf("(%d,%d)",ls[i].x,ls[i].y);
if(i<step-1)
{
printf("->");
}
}
printf("\n");
}
else
{
int tx,ty;
for(int i=0;i<4;i++)
{
tx=x1+dx[i];
ty=y1+dy[i];
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&vis[tx][ty]==0&&mp[tx][ty]==1)
{
ls[step].x=tx;
ls[step].y=ty;
step++;
vis[tx][ty]=1;
dfs(tx,ty);
vis[tx][ty]=0;
step--;
}
}
}
}
int main()
{
int sx,sy;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&mp[i][j]);
}
}
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
ls[0].x=sx;
ls[0].y=sy;
f=0;
step=1;
vis[sx][sy]=1;
dfs(sx,sy);
if(f==0)
{
printf("-1\n");
}
return 0;
}
给定M×N的矩阵,其中的每个元素都是-10到10之间的整数。你的任务是从左上角(1,1)走到右下角(M,N),每一步只能够向右或者向下,并且不能够走出矩阵的范围。你所经过的方格里面的数字都必须被选取,请找出一条最合适的道路,使得在路上被选取的数字之和是尽可能小的正整数。
取数字问题
输入格式:
输入第1行是两个整数M和N,(2<=M<=10,2<=N<=10),分别表示矩阵的行和列的数目。接下来M行,每行包括N个整数,就是矩阵中的每一行的N个元素。
输出格式:
输出只有一行,就是一个整数,表示所选道路上数字之和所能达到的最小正整数。如果不能达到任何正整数,输出-1。
#include <stdio.h>
int max=10000000;
int a[30][30],n,m;
void f(int i,int j,int sum);
int main()
{
int i,j;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
}
}
f(1,1,0);
if(max==10000000)
{
max=-1;
}
printf("%d\n",max);
return 0;
}
void f(int i,int j,int sum)
{
sum+=a[i][j];
if(i<n)
{
f(i+1,j,sum);
}
if(j<m)
{
f(i,j+1,sum);
}
if(i==n&&j==m&&sum<max&&sum>0)
{
max=sum;
}
}
输入数据有多组。每组数据的第一行为以正整数n(0 < n < 100000),表示有n个馅饼掉在这条小径上。在结下来的n行中,每行有两个整数x,T(0 <= T < 100000),表示在第T秒有一个馅饼掉在x点上。同一秒钟在同一点上可能掉下多个馅饼。n=0时输入结束。
免费馅饼
输出格式:
每一组输入数据对应一行输出。输出一个整数m,表示gameboy最多可能接到m个馅饼。
提示:本题的输入数据量比较大,建议用scanf读入,用cin可能会超时。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
int dp[100005][15];// dp[时间][坐标]
int n, x, t;
int main()
{
while(~scanf("%d", &n) && n){
memset(dp, 0, sizeof(dp));
int maxn = -0x3f3f3f3f;// 每一组的初始化不能忘!!
for(int i = 0; i < n; i++){
scanf("%d%d", &x, &t);
dp[t][x]++;
maxn = max(maxn, t);
}// 找到最大时间
for(int i = maxn - 1; i >= 0; i--){// 反向存储
for(int j = 0; j <= 10; j++)
dp[i][j] += max(dp[i+1][j], max(dp[i+1][j-1], dp[i+1][j+1]));
}// 存下三个坐标中饼最多的那个(两次比较,一次搞定)
printf("%d\n", dp[0][5]);// 第一个数就是最多的馅饼个数
}
return 0;
}