金石山脉有n个山峰,一字排开,从西向东依次编号为1, 2, 3, ……, n。编号为i的山峰高度为hi。每个山峰的高度两两不同
小木示从西向东依次爬过这n个山峰,到每一个山峰的山顶的时候,他都会往西边眺望,并且会记录下自己能看到的山峰的个数。
(比如说小木示 现在在4号山峰,前四号山峰的高度分别为9,4,5,1。他现在能看到的山峰个数就是2,因为第二个山峰被第三个山峰挡住了)
严格的来说,小木示在i位置的时候,对于一个山峰j (j < i),如果不存在一个山峰k满足hj < hk (j < k < i)。则山峰j是可见的。
小木示把自己记录的山峰的个数加和作为这次爬山的快乐值,现在给你n个山峰的高度,求小木示的快乐值。
多组输入,首先输入一个n(1 <= n <= 10^6),表示山峰的个数。
接下来一行n个数,表示对应山峰的山峰的高度(1 <= h <= 10^6)。
4
利用栈的思想。
数组模拟栈或者栈函数。
01 | #include <bits/stdc++.h> |
18 | while (!s.empty()&&s.top()<a) |
01 | #include <bits/stdc++.h> |
06 | int a[1000005],n,x,top; |
裸题!熟悉二叉树的各种序列的互推方式。知道前中或前后去建树,然后进行各种遍历,四中遍历方式 要非常熟悉。
Time Limit: 1000MS
Memory Limit: 65536KB
Problem Description
已知一棵二叉树的前序遍历和中序遍历,求二叉树的后序遍历和层序遍历。
Input
输入数据有多组,第一行是一个整数t (t<1000),代表有t组测试数据。每组包括两个长度小于50 的字符串,第一个字符串表示二叉树的先序遍历序列,第二个字符串表示二叉树的中序遍历序列。
Output
每组第一行输出二叉树的后序遍历序列,第二行输出二叉树的层次遍历序列。
Example Input
2
abdegcf
dbgeafc
xnliu
lnixu
Example Output
dgebfca
abcdefg
linux
xnuli
01 | #include <bits/stdc++.h> |
09 | struct node *creat( int n, char a[], char b[]) |
25 | root->l=creat(t,a+1,b); |
27 | root->r=creat(n-1-t,a+1+t,p+1); |
30 | void houxu( struct node*root) |
40 | void cengxu( struct node*root) |
42 | struct node *temp[100]; |
51 | temp[in++]=temp[out]->l; |
52 | temp[in++]=temp[out]->r; |
61 | struct node*root= new node; |
Time Limit: 1000MS
Memory Limit: 65536KB
Problem Description
Old MacDonald Had A Farm, cycyk~
老麦克唐纳德有一个农场,农场里有马、兔、牛三种动物。开始时他有母马、母兔、母牛各 1 只。
对于每头母马,它从第二年起每年年初生一头小母马。每头小母马从第二个年头开始,每年年初也生一头小母马。
对于每只母兔,它从第二年起每年年初生一只小母兔。每只小母兔从第三个年头开始,每年年初也生一只小母兔。
对于每头母牛,它从第二年起每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。
现在老麦克唐纳德想知道,第 n 年时他总共有多少只动物(这里只考虑母马、母兔和母牛)?
Input
输入数据有多组(数据组数不超过 100),到 EOF 结束。
对于每组数据,输入 1 行,包含 1 个整数 n (1 <= n <= 30),表示询问的年数。
Output
对于每组数据,输出 1 行,包含 1 个整数,表示答案。
Example Input
Example Output
Hint
第 1 年时,老麦克唐纳德有母马 1 头、母兔 1 只、母牛 1 头。
第 2 年时,老麦克唐纳德有母马 2 头、母兔 2 只、母牛 2 头。
第 3 年时,老麦克唐纳德有母马 4 头、母兔 3 只、母牛 3 头。
第 4 年时,老麦克唐纳德有母马 8 头、母兔 5 只、母牛 4 头。
01 | #include <bits/stdc++.h> |
03 | int a[35]={1,2,4,8},b[35]={1,2,3,5},c[35]={1,2,3,4}; |
16 | cout<<a[n-1]+b[n-1]+c[n-1]<<endl; |
Time Limit: 5MS
Memory Limit: 500KB
Problem Description
给定n(1<=n<=100000)个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n。 例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20。
注意:本题目要求用动态规划法求解,只需要输出最大子段和的值。
Input
第一行输入整数n(1<=n<=100000),表示整数序列中的数据元素个数;
第二行依次输入n个整数,对应顺序表中存放的每个数据元素值。
Output
Example Input
Example Output
这道题是典型的求最大连续子序列和的问题。我们首先回顾一下动态规划法求最大连续子序列和的方法:
int max_sum = 0, this_sum = 0;
for(int i=0; i<n; ++i) {
this_sum += a[i];
if(this_sum > max_sum)
max_sum = this_sum;
if(this_sum < 0)
this_sum = 0;
}
参照以上代码,我们举一个例子来说明:
对于序列 3 -2 4 -6 5 1,
遍历到 3 时:当前子序列为 3,this_sum = 3,max_sum = 3;
遍历到 -2 时:当前子序列为 3 -2,this_sum = 1,max_sum = 3;
遍历到 4 时:当前子序列为 3 -2 4,this_sum = 5,max_sum = 5;
遍历到 -6 时:当前子序列为 3 -2 4 -6,this_sum = -1,此时当前子序列和为负,如果不抛弃当前子序列而继续累加的话,下次的子序列和等于下一个元素加上一个负数,即 -1 + 5 = 4 < 5,必然比直接从下一个元素开始重新计算的子序列和要小,故抛弃当前子序列和,从下一个元素开始重新计算子序列和。this_sum = 0,max_sum = 5;
遍历到 5 时:当前子序列为 5,this_sum = 5,max_sum = 5;
遍历到 1 时:当前子序列为 5 1,this_sum = 6,max_sum = 6;
故得到结果为 6。
回到硬币问题上来,我们可以把翻硬币的过程相对初始状态比较,反面翻到正面就是正面的个数 +1,而正面翻到反面就是正面的个数 -1,因此我们可以把这个相对状态看作是一个由 1 和 -1 组成的序列,按照上面的方法求解即可。
这样我们就可以写出本题的代码了:
#include <cstdio>
using namespace std;
int main(int argc, char const *argv[]) {
int n, a[1000];
while(~ scanf("%d", &n)) {
int sum = 0;
for(int i=0; i<n; ++i) {
scanf("%d", &a[i]);
if(a[i] == 1) sum++;
}
int max_sum = 0, this_sum = 0;
for(int i=0; i<n; ++i) {
if(a[i] == 0)
this_sum++;
else
this_sum--;
if(this_sum > max_sum)
max_sum = this_sum;
if(this_sum < 0)
this_sum = 0;
}
printf("%d\n", sum + max_sum);
}
return 0;
}
动态规划?
Time Limit: 1000ms Memory limit: 65536K
题目描述
动态规划作为《运筹学》的一个分支,被广泛的用于解决较为复杂的经济管理问题,以达到的最优抉择,获得最大经济收益为目的。也因其多变性,非常的频繁的出现在信息学竞赛的赛场上。
动态规划的核心思想为不断将问题分解为子问题,一直到可以较容易的得到最优答案,再去决定其父问题的决策,因为很大程度的避免了重复子问题的抉择,故可以节约大量时间。
现在问题来了,有一个一维数组,存储了n个正整数,下标依次为0,1,2,….,n-1。
现在要从中选取一部分数,你要给出一个选择方案使得你的方案满足下列要求:
1. 这部分元素的下标应满足st,st+5, st+5*2 , st+5*3, … , st+5*x (0 <= st < n ,st <= st+5*x < n)。
2. 在满足第一条要求的方案中,应选取其累加和最大的一种的方案。
输入
多组输入。
对于每组输入:
第一行输入一个n(1 <= n <= 100000)。
接下来的一行有n个整数y(-100000 <= y <= 100000)。
输出
对于每组数据,输出一个整数代表你的方案的累加和。
示例输入
10
1 2 3 4 5 6 7 8 9 10
3
1 -10 2
3
-1 -2 -3
示例输出
15
2
-1
提示
来源
zmx
解题思路
这道题是典型的求最大连续子序列和的问题。其求法可以参考我的这篇文章。
理解了最大连续子序列和的算法,这道题就不难解决了。由于每种方案的元素下标都满足 st + 5*n,因此我们可以把 st 从 0 到 4 的一共 5 种方案看作 5 个可找到的最长序列,对每个序列求其最大连续子序列和,最后再从这 5 个最大连续子序列和中找出最大的即得到结果。
这样我们就可以写出本题的代码了:
#include <cstdio>
using namespace std;
int n, a[100000];
int Solve(int st);
int main(int argc, char const *argv[]) {
while(~ scanf("%d", &n)) {
for(int i=0; i<n; ++i) {
scanf("%d", &a[i]);
}
int max_sum = Solve(0), sum;
for(int i=1; i<5 && i<n; ++i) {
sum = Solve(i);
if(sum > max_sum)
max_sum = sum;
}
printf("%d\n", max_sum);
}
return 0;
}
int Solve(int st) {
int max_sum = -100000, this_sum = 0;
for(int i=st; i<n; i+=5) {
this_sum += a[i];
if(this_sum > max_sum)
max_sum = this_sum;
if(this_sum < 0)
this_sum = 0;
}
return max_sum;
}
- 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
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
巨斧砍大树
Time Limit: 1000 Memory Limit: 65536
Description
阿福最近练就了一个新的招式:巨斧砍大树。这个招式可以砍掉一颗二叉搜索树的某个子树。现在,阿福面前有一颗 n 个结点的二叉搜索树,他要使用 m 次招式,于是他想询问你每次使用「巨斧砍大树」后二叉搜索树会被砍成什么样子。
二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分别为二叉搜索树。
Input
第 1 行输入 2 个整数 n, m (1 <= n, m <= 10)。表示二叉搜索树的结点个数和招式使用次数。
第 2 行输入 n 个空格隔开的整数 v (1 <= v <= 10),表示二叉搜索树是以此序列顺序插入生成的二叉树(保证互不相同)。
接下来输入 m 行,每行一个整数 w (1 <= w <= 10),表示阿福要砍掉结点上数值为 w 的子树(保证 w 是初始二叉树上存在的数值)。
Output
对于每次砍树,如果成功砍掉子树,则先输出一行 "Cut x",其中 x 为被砍掉子树的根节点上的数值。如果要砍掉的结点在之前已被砍掉,则输出一行 "Already cut x",x 的含义同上。
随后输出一行,表示此次砍树结束后当前二叉树的中序遍历结果,以空格分隔(行末没有多余空格,如果整颗二叉树已为空,则输出一行空行)。
Sample Input
5 5
1 3 2 4 5
5
2
3
4
1
Sample Output
Cut 5
1 2 3 4
Cut 2
1 3 4
Cut 3
1
Already cut 4
1
Cut 1
代码:
#include <stdio.h>
#include <stdlib.h>
/*
1、本题思想其实很简单,只需要建立一个排序二叉树,然后查找数据元素
所在二叉树的位置,找到以后将其根节点变为空,同时将其左右子树变为空
2、本题输出遍历后的数据元素时,因为有具体要求(最后一个元素后面无空格)
所以我们可以使用一个数组来保存元素*/
typedef int element ;
typedef struct node
{
element data;
struct node *lchild,*rchild;
} Bnode,*BiTree;
int a[100];
int k;int g;
//建立排序二叉树
BiTree creat(BiTree root,int k)
{
if(!root)
{
root=(BiTree )malloc(sizeof(Bnode));
root->data=k;
root->lchild=NULL;
root->rchild=NULL;
}
else
{
if(k>root->data)
root->rchild=creat(root->rchild,k);
if(k<root->data)
root->lchild=creat(root->lchild,k);
}
return root;
}
//在二叉树中查找到具体元素,并将其和左右子树变为空
BiTree find(BiTree root,int k)
{
if(root)
{
if(root->data==k) //找到数据元素,并将标记记为1;
{
root->lchild=NULL;
root->rchild=NULL;
root=NULL;
g=1;
}
else //左右寻找数据元素
{
if(k<root->data)
root->lchild=find(root->lchild,k);
if(k>root->data)
root->rchild=find(root->rchild,k);
}
}
else //找不到数据元素,标记为0;
{
g=0;
}
return root;
}
void midprint(BiTree root) //输出中序遍历结果
{
if(root)
{
midprint(root->lchild);
a[k++]=root->data;
midprint(root->rchild);
}
}
int main()
{
BiTree root=NULL;
int n,m;
int i;
int t;int p;
scanf("%d %d",&n,&m);
for(i=0; i<n; i++)
{
scanf("%d",&t);
root=creat(root,t);
}
while(m--)
{
k=0;
scanf("%d",&p);
root=find(root,p);
if(g==0) //当标记为0时,说明以此元素为根节点的值为空,即该元素已被砍掉
printf("Already cut %d\n",p);
if(g==1) //当标记为1时,说明该元素还为被删除
{
printf("Cut %d\n",p);
midprint(root);
if(k==0) //k为0,说明整个二叉树为空,无数据元素
printf("\n");
else //k不为0,输出数组元素
{
for(i=0;i<k-1;i++)
printf("%d ",a[i]);
printf("%d\n",a[k-1]);
}
}
}
return 0;
}