1.连续最大和
题目
一个数组有 N 个元素,求连续子数组的最大和。 例如:[-1,2,1],和最大的连续子数组为[2,1],其和为 3
输入描述:
输入为两行。 第一行一个整数n(1 <= n <= 100000),表示一共有n个元素 第二行为n个数,即每个元素,每个整数都在32位int范围内。以空格分隔。
输出描述:
所有连续子数组中和最大的值。
题目分析
法一:可以找出规律,如果当前和小于0,那么可以把这个当前值抛弃,因为加上一个负数(包括0)还不如不加,把当前数设置为当前和。如果当前和是正数,则把当前数加进去更新当前和,这个时候判断下当前和是否大于最大连续和,是的话就更新最大连续和,否则,不更新最大连续和,只更新当前和。需要注意的是:需要设置一个布尔变量,判断是因为输入无效数据返回的0还是本身最大连续和就是0.
法二:用动态规划的算法。用f(i)表示第一个数字结尾的子数组的最大和,那么我们需要求出max{f(i)},其实0<=i<=n。然后用递归来解。代码同法一是一样的,max[f(i)]就是greatsum,f(i)就是cursum。
f(i) =data[i] i==0 || f(i-1)<=0
=f(i-1)+data[i] i!=0 && f(i-1)>0
代码
#include<iostream>
using
namespace
std;
#include<vector>
bool
g_invalid=
false
;
//判断返回值为0 还是因为是无效数据返回的0
int
getMax(vector<
int
> nums,
int
n)
{
if
(n<=0)
{
g_invalid=
true
;
return
0;
}
g_invalid=
false
;
int
cursum=0;
int
greatsum=0x80000000;
for
(
int
i=0;i<n;i++)
{
if
(cursum<=0)
cursum=nums[i];
else
cursum+=nums[i];
if
(cursum>greatsum)
greatsum=cursum;
}
return
greatsum;
}
int
main()
{
int
total_numbers=0;
cin>>total_numbers;
vector<
int
> s;
int
tmp=0;
for
(
int
i=0;i<total_numbers;i++)
{
cin>>tmp;
s.push_back(tmp);
}
cout<<getMax(s,total_numbers);
return
0;
}
|
2.餐馆
题目
某餐馆有n张桌子,每张桌子有一个参数:a 可容纳的最大人数; 有m批客人,每批客人有两个参数:b人数,c预计消费金额。 在不允许拼桌的情况下,请实现一个算法选择其中一部分客人,使得总预计消费金额最大
输入描述:
输入包括m+2行。 第一行两个整数n(1 <= n <= 50000),m(1 <= m <= 50000) 第二行为n个参数a,即每个桌子可容纳的最大人数,以空格分隔,范围均在32位int范围内。 接下来m行,每行两个参数b,c。分别表示第i批客人的人数和预计消费金额,以空格分隔,范围均在32位int范围内。
输出描述:
输出一个整数,表示最大的总预计消费金额
题目分析
首先来看数据结构,对于餐桌而言,需要知道它的容纳数量以及是否以及被占座了,对于顾客而言,我们需要知道它的就餐人数和消费金额,因此,采用类或者结构体来存储这两个变量最合适,然后将读入的类或者结构体存入到vector里面,因为容器里面存储的元素可以是自定义的类或者数据结构,对于排序也比较方便。接下来分析如何收益最大化,我们当然希望土豪先入座,而且坐一个符合他们就餐人数的容纳量最小的桌子,这就需要我们将顾客这个类进行排序,先按消费金额进行降序排列,在消费金额相同的情况下,按人数的多少升序排列。为了符合坐一个符合他们就餐人数的容纳量最小的桌子,对应的餐桌这个类也应该按照人数进行升序排列。这样,在满足能够容纳就餐人数且没有被占座的情况下,依次安排顾客就座,就可以达到收益最大化。需要注意的是,收益总金额的数据类型,应该定义为long long类型,否则会引起溢出。
代码
#include<iostream>
#include<algorithm>
#include <vector>
using
namespace
std;
class
Customer
//声明顾客类
{
public
:
int
num;
//每批顾客人数
int
money;
//每批顾客预计消费金额
Customer()
{
num = 0;
money = 0;
}
};
class
Table
//餐桌类
{
public
:
int
num;
//每张餐桌能容纳人数
int
state;
//每张餐桌状态,0为空,1为满
Table()
{
num = 0;
state = 0;
}
};
//先按照消费金额进行降序,金额一样时按照人数升序
bool
sortByAll(
const
Customer &c1,
const
Customer &c2)
{
if
(c1.money > c2.money)
return
true
;
else
if
(c1.money < c2.money)
return
false
;
else
return
c1.num < c2.num;
}
//餐桌按能容纳人数升序
bool
sortBynum(
const
Table &t1,
const
Table &t2)
{
return
t1.num < t2.num;
}
int
main()
{
int
n, m;
int
i, j;
long
long
Max_money = 0;
cin >> n >> m;
vector<Table> vec_T(n);
vector<Customer> vec_C(m);
for
(i = 0;i < n;i++)
//输入各餐桌能容纳人数
cin >> vec_T[i].num;
for
(j = 0;j < m;j++)
//输入顾客人数及预计消费金额
cin >> vec_C[j].num >> vec_C[j].money;
sort(vec_C.begin(), vec_C.end(), sortByAll);
//顾客按金额降序,按人数升序
sort(vec_T.begin(), vec_T.end(), sortBynum);
//餐桌按能容纳人数升序
for
(i = 0;i < m;i++)
//按消费金额依次安排入座
for
(j = 0;j < n;j++)
if
(vec_C[i].num <= vec_T[j].num && vec_T[j].state == 0)
{
vec_T[j].state = 1;
Max_money += vec_C[i].money;
break
;
}
cout << Max_money << endl;
return
0;
}
|
3.地下迷宫
题目
小青蛙有一天不小心落入了一个地下迷宫,小青蛙希望用自己仅剩的体力值P跳出这个地下迷宫。为了让问题简单,假设这是一个n*m的格子迷宫,迷宫每个位置为0或者1,0代表这个位置有障碍物,小青蛙达到不了这个位置;1代表小青蛙可以达到的位置。小青蛙初始在(0,0)位置,地下迷宫的出口在(0,m-1)(保证这两个位置都是1,并且保证一定有起点到终点可达的路径),小青蛙在迷宫中水平移动一个单位距离需要消耗1点体力值,向上爬一个单位距离需要消耗3个单位的体力值,向下移动不消耗体力值,当小青蛙的体力值等于0的时候还没有到达出口,小青蛙将无法逃离迷宫。现在需要你帮助小青蛙计算出能否用仅剩的体力值跳出迷宫(即达到(0,m-1)位置)。输入描述:
输入包括n+1行: 第一行为三个整数n,m(3 <= m,n <= 10),P(1 <= P <= 100) 接下来的n行: 每行m个0或者1,以空格分隔
输出描述:
如果能逃离迷宫,则输出一行体力消耗最小的路径,输出格式见样例所示;如果不能逃离迷宫,则输出"Can not escape!"。 测试数据保证答案唯一
题目分析
还没有熟悉dfs,后面再更新,这里的代码参考牛客网上的。代码
#include<iostream>
#include<vector>
using namespace std;
#define VISITED 2;
int n,m,p;
int maze[10][10];//存迷宫
int dir[4][2]={{0,-1},{0,1},{-1,0},{1,0}};//左右上下
int cost[4]={-1,-1,-3,0};
int final_p=-200;
//存储各点的数据结构
struct mazepoint
{
mazepoint(int _x,int _y):x(_x),y(_y){}
int x,y;
};
//存储最终的最优路径
vector<mazepoint> minCostPath;
//存储每次遍历的路径
vector<mazepoint> pathStack;
void printPath(const vector<mazepoint>& path)
{
for(int i=0;i<path.size();i++)
{
cout<<"["<<path[i].x<<","<<path[i].y<<"]";
if(i<path.size()-1)
{
cout<<",";
}
}
}
void search(int x,int y,int cur_P)
{
pathStack.push_back(mazepoint(x,y));
maze[x][y]=VISITED;
//到达终点了且还有体力
if(x==0 && y==m-1 && cur_P>=0)
{
if(cur_P>final_p)//更新final_p,如果下一次找出来的路径比当前的这个路径所剩的体力更多,则继续更新
{
final_p=cur_P;
minCostPath=pathStack;
}
pathStack.pop_back();
maze[x][y]=1;// 为了回退至之前的节点,将当前结点弹出
return ;
}
//没到终点还有体力,向上下左右四个方向探索,计算相应的消耗,如果新的点在边界内且为可达点,递归调用srearch函数
if(cur_P>0)
{
for(int i=0;i<4;++i)
{
int nx=x+dir[i][0];
int ny=y+dir[i][1];
int nP=cur_P+cost[i];
if(nx>=0 && nx<n && ny>=0 && ny<m && maze[nx][ny]==1)
search(nx,ny,nP);
}
}
pathStack.pop_back(); // 为了回退至之前的节点,将当前结点弹出
maze[x][y] = 1; // 注意:之前maze[x][y]被标记为VISITED(值为2),回退后应该将其还原为1
}
int main()
{
cin>>n>>m>>p;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>maze[i][j];
}
}
search(0,0,p);//搜索最短路径
if(final_p!=-200)//能走出去
{
printPath(minCostPath);
}
else
cout<<"Can not escape!";
return 0;
}
4.末尾0的个数
题目
输入一个正整数n,求n!(即阶乘)末尾有多少个0? 比如: n = 10; n! = 3628800,所以答案为2输入描述:
输入为一行,n(1 ≤ n ≤ 1000)
输出描述:
输出一个整数,即题目所求
题目分析
要产生0,则必然由2和5相乘而来,所以这道题成了求因子数,显然2的因子是要多于5的因子的,因此,结果末尾由多少个0取决于它由多少个5的因子,我们可以遍历1到n,然后看它由多少个5的因子。但是这样做不是最佳的,只有5的倍数才有5这个因子,能被5整除提供1个0,能被25整除提供2个0,能被125整除提供3个0,所以
结果=n/5+n/25+n/125...
代码
#include<iostream>
#include<vector>
using
namespace
std;
int
main()
{
int
n;
cin>>n;
int
res;
while
(n)
{
res+=n/5;
n=n/5;
}
cout<<res<<endl;
}
5.进制转换
题目
给定一个十进制数M,以及需要转换的进制数N。将十进制数M转化为N进制数输入描述:
输入为一行,M(32位整数)、N(2 ≤ N ≤ 16),以空格隔开。
输出描述:
为每个测试实例输出转换后的数,每个输出占一行。如果N大于9,则对应的数字规则参考16进制(比如,10用A表示,等等)
题目分析
短除取余,逆序,所以考虑用栈的结构去存储m%n,然后把栈一个个弹出来,这里要注意负数的情况,可以先把负数转成正数再处理
代码
#include <stack>
using namespace std;
int main(int argc, const char * argv[])
{
int M,N;
cin>>M>>N;
stack<char> answer;
if(M<0)
{
cout<<"-";
M=-M;
}
while(M!=0)
{
if(M%N<10)
{
answer.push(char(M%N+'0'));
M/=N;
}
else
{
answer.push(char(M%N-10+'A'));
M/=N;
}
}
while(!answer.empty())
{
cout<<answer.top();
answer.pop();
}
return 0;
}
6.数字和为sum的方法数
题目
给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。
输入描述:
输入为两行: 第一行为两个正整数n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000) 第二行为n个正整数A[i](32位整数),以空格隔开。
输出描述:
输出所求的方案数
题目分析
代码
//动态规划 dp[i][j]表示用前i个值组成和为j的方案个数//结果int类型存不下,得64位的数据类型,dp也不能在main函数里面定义,栈存不下,因此存在全局数据区
#include<iostream>
#include<algorithm>
using namespace std;
long long dp[1000][1000];
int main()
{
int n,sum;
cin>>n>>sum;
int p[1000];
for(int i=1;i<=n;i++)
cin>>p[i];
//初始化dp,前i个数组组成和为0的方案只有1种,就是什么都不选
for(int i=0;i<n;i++)
{
dp[i][0]=1;
}
//初始化dp,用0个元素没法组成1至sum
for(int j=1;j<sum;j++)
{
dp[0][j]=0;
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=sum;j++)
{
if(p[i]<=j)
dp[i][j]=dp[i-1][j]+dp[i-1][j-p[i]];
else
dp[i][j]=dp[i-1][j];
}
}
cout<<dp[n][sum]<<endl;
return 0;
}