小K没事干,他要搬砖头,为了达到较好的减肥效果,教练规定的方式很特别:
每一次,小K可以把两堆砖头合并到一起,消耗的体力等于两堆砖头的重量之和。
经过 n-1次合并后, 就只剩下一堆了。小K在搬砖头时总共消耗的体力等于每次合并所耗体力之和。小K为了偷懒,希望耗费的体力最小。
例如有 3堆砖头,数目依次为 1、2、9 。可以先将 1 、 2 堆合并,新堆数目为3 ,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为12 。所以总共耗费体力 =3+12=15。可以证明 15为最小的体力耗费值。
共两行。
第一行是一个整数 n(1≤n≤1000) ,表示砖头堆数。
第二行n个整数,每个整数表示每堆砖头的砖头块数。
一个整数,也就是最小的体力耗费值。
3
1 2 9
15
这个问题很简单,只需要每次挑两个最小的加到sum里,再将两个数之和放回到数组中,并使得数组有序,操作n-1次之后就得到了想要的解。
#include
using namespace std;
int main()
{
int n,a[1000],sum=0,i;
cin >> n;
for ( i = 0; i < n; i++)
{
cin >> a[i];
}
sort(a, a + n);
// 计算两个最小数之和,加入到sum中,并且放回到原数组中使其有序
for ( i = 0; i < n - 1; i++)
{
int temp = a[i + 1] + a[i];//记录前两个最小的值
int k = i + 2;//k为第三个的下标
// 找到一个合适的位置放置 temp
while (a[k] < temp && k < n)
{// 比较第三个和前两个的和,若第三个比前两个要小
// 这里 a[k-1]是无效位,因为已经将a[k-1]和a[k-2]的值赋给了temp,可以随意覆盖。
a[k - 1] = a[k];//前移
k++;
}
// 找到正确的位置将数字放入该位置
a[k - 1] = temp;
sum += temp;
}
cout << sum << endl;
return 0;
}
给定一个非负整数数组,假定你的初始位置为数组第一个位置。数组中的每个元素代表你在那个位置能够跳跃的最大长度。你的目标是到达最后一个下标位置,并且使用最少的跳跃次数。
输入一组非负整数数组,数组长度不超过500。
最少经过几次跳跃,可以到达最后一个位置。
2 3 1 1 4
2
#include
using namespace std;
int a[501]={0},ct=0;//ct表示跳跃的次数
int jump(int i,int len)
{
int k,j=0,l,max=0;
// 已经退出了
if(i>=len-1) return 0;
// 还要继续跳
k=a[i];ct++;
// 再向前跳k步可以跳出范围
if(i+k>=len-1) return 0;
// 找出未来a[i]个元素中能跳到的最远距离
for(l=i+1;l<=i+k;l++)
{
// 设置一个max用于记录能跳到的最大距离
// 如果在位置 l 跳长度为 a[l] 的距离,到达 l+a[l]
// 如果 l+a[l] > max 就将下一个落点设置到 j=l 处
// 按此方法,每次都跳到该区间中能到达的最远位置,就能得到最优解
if(max<=l+a[l])
{
//更新数据
j=l;max=l+a[l];
}
}
jump(j,len); //跳到最远的数组里
}
int main()
{
int x,len,i=0;
while(cin>>x)
{
a[i++] = x;
}
len = i;//len表示数组长度
jump(0,len);
cout<<ct<<endl;
return 0;
}
给出n个区间的起点和终点,求最少使用其中多少个区间可以将所有区间所在的区域完全覆盖。(测试的数据确保这1点)。
第1行一个整数n,表示n个区间;
第2行开始n行,每行2个整数,表示一个区间范围。
类似[1,4][5,6]被认为是覆盖了[1,6]。
从起点开始,按区间先后顺序,输出选中的区间。所选的区间应尽可能向终点扩展。
7
1 5
1 6
3 6
1 7
6 9
9 10
7 9
1 7
6 9
9 10
输入区间,按照区间左端点将区间进行排序,左端点相同的区间按照右端点排序。
在给定的区间内找到最小值和最大值作为做起点和终点。
初始右区间设定为起点,左区间设定为起点。
#include
using namespace std;
struct Area
{
int left, right;
}area[100],r[100];
// 定义比较区间大小的规则
bool cmp(Area a,Area b)
{
if (a.left < b.left)
return true;
else if (a.left == b.left && a.right < b.right)
return true;
else return false;
}
int main()
{
// 初始化
int n,i,cnt=0;
cin >> n;
for ( i = 0; i < n; i++)
{
cin >> area[i].left >> area[i].right;
}
// 排序
sort(area, area + n, cmp);
int right = area[0].left - 1;// 初始的右端点
int end = area[n - 1].right;// 终点
// 遍历每个区间段,更新右端点的范围
for (i = 0; i < n-1;)
{
int max_right = area[i].right;// 定义能得到的最大右端点
int max_index = i;
while (area[i].left <= right + 1 && i < n)
{// 该区间左边小于当前的右端点,+1 这种情况代表两个区间是紧挨着的
if (area[i].right > max_right)
{
max_right= area[i].right;//记录能到达的最大的右端点的值
max_index = i;//记录能到达的最大的右端点的区间编号
}
i++;
}
// 这里每次循环的右端点是受限的,只有一小部分区间会参与
// 随着右端点的右移,算法不断接近最优解
right = max_right;//更新右的值
r[cnt++] = area[max_index];//数组中记录被选择的区间
i = max_index;
if (right == end) break;//嘿嘿终于到终点啦~~结束
}
for (i = 0; i < cnt; i++)
{
cout << r[i].left << " " << r[i].right << endl;
}
return 0;
}
一条街的一边有几座房子。因为环保原因居民想要在路边种些树,路边的地区被分割成块,并被编号成1…N;
每个部分为一个单位尺寸大小并最多可种一棵树,每个居民想在门前种些树并指定了三个号码B,E,T,这三个数表示该居民想在B和E之间最少种T棵树。
当然,B≤E,居民必须记住在指定区不能种多于区域地块数的树,所以T≤E-B+l。
居民们想种树的各自区域可以交叉。你的任务是求出能满足所有要求的最少的树的数量。
第一行包含数据N,区域的个数;
第二行包含H,房子的数目;
下面的H行描述居民们的需要:B E T。
输出能满足所有要求的最少的树的数。
9
4
1 4 2
4 6 2
8 9 2
3 5 2
5
#include
#include
using namespace std;
struct request
{//定义一个结构体来存储居民的需求
int B,E,T;//B:左端点,E:右端点,T:需要种的树的数量
}a[500];
bool cmp(request a,request b)
{
if(a.E==b.E)
return a.B<b.B;
return a.E<b.E;
}
int main()
{
int B,E,T;
int N,H;
cin>>N>>H;
for(int i=1;i<=H;i++)
{
cin>>a[i].B>>a[i].E>>a[i].T;
}
sort(a+1,a+1+H,cmp);//按照右端点的大小对需求进行排序
int num=0;//num表示树的总数
int road[10000]={0};//用road数组记录道路上是否已经种树
for(int i=1;i<=H;i++)//遍历每一条需求
{
int ans=0;
for(int j=a[i].B;j<=a[i].E;j++)
ans+=road[j];//ans表示B到E已经种了多少棵树
for(int j=a[i].E;j>=a[i].B&&ans<a[i].T;j--)//尽量从右开始种树
{
if(!road[j])//如果tr[j]的位置上还没被种树的话,种树
{
road[j]=1;
ans++;
num++;
}
}
}
cout<<num<<endl;
return 0;
}