——引言:这是我的第一篇博客文章 记录时间于2016年12月16日23:06:49——
- 开博客的原因:一来是因为自己本身也喜欢记录一些感想和笔记,二来也受到了舍友的一部分影响,三来觉得大学生涯该留下点什么以后好回忆,于是也就屁跌学了人家;
- 博客记录的内容不限(比较自由),不过主要以本专业的计算机类技术为主;
- 下面的内容主要是本人于大二上学期在成电做的一道ACM程序设计趣味题,我大概是把周六的一下午都花在了编写这道程序上(gg),一开始反复提交过许多次,结果每次提交编译都有不同的错误提示,做到后来答案基本正确但是时间复杂度又超标,无奈又花了不少时间修改算法和程序,所以写出了不同复杂度的两个版本。虽坎坷,也算有所收获;以上算是做了简单的申明吧。
Okay 以下是标题内容
B - 保护果实
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
A有一棵果树,但是树上的果子总是还没有成熟就被B偷偷摘走了。
于是,A想买一些栅栏想把果树围起来,让B再也偷不了果子。
卖栅栏的人有N块栅栏,每块栅栏长度为ai。但是,卖栅栏的人与B关系很好,他不想随便卖给A。
于是,他规定,如果要买第i块栅栏,那么必须要先买第i-1块栅栏(第一块栅栏除外)。
同时,A是一个不想浪费的人,他想把他买的所有栅栏都用上,并且,让栅栏围成的图形是个多边形。
那么,A最少需要买多少块栅栏呢。
Input
一共有两行。
第一行一个数,表示总共的栅栏数 N(N≤1,000,000) 。
第二行有N个数,第i个数表示第i块栅栏的长度 ai (ai之和不会超过int的上界) 。
Output
输出一个数,表示最少需要的栅栏数,如果无解输出-1.
Sample input and output
Sample Input | Sample Output |
---|---|
3 3 4 5 | 3 |
Source
Solution 1
- 理解题意,只能按给定的顺序从前往后顺序进行购买;
- 要围成一个栅栏(多边形),排除1,2两条边无法相围形成多边形的这种情况;
其余n>=3,只要最长的一条边小于剩余小边之和就可以构成多边形(基于两点之间直线最短原理);
- 使用a[]数组记录输入数据,拷贝的b数组用sort排序,使得b数组最后一个数始终最大;
- 算法时间复杂度:o( n*n*log(n) )//因为一个for循环中嵌套了一个sort函数//结果超时
#include<iostream>
#include<algorithm>
using namespace std;
#define x 1000000
int a[x], b[x];//大数组全局定义
int main(void)
{
int i, N, sum=0;
cin >> N;//总共的栅栏数
for (i = 0; i < N; i++)
{
cin >> a[i];//依次输入到a[]
b[i] = a[i];//并拷贝一份到b[] 储存a[]排序后的内容
}
if (N <= 2)
cout << "-1";//小于两条边不能构成封闭多边形
else
{
sort(b, b +2);//首先对a[0],a[1]排序,得到b[0],b[1]
sum = b[0];
for (i = 2; i <= N ; i++)
{
if (i == N)//判断不能构成闭合多边形的终止条件,因a[0]~a[N]判定的数据量超过了本身的N个数据
{
cout << "-1";
break;
}
if (a[i] < b[i-1])//和的条件判断,每一个即将放入的a[i]都和上一个排好序的最大值b[i-1]比较,目的是为了使sum加上小的
sum += a[i];
else
sum += b[i-1];
sort(b, b + i + 1);//对新加入的a[i]进行排序得到b[0]~b[i]
if (b[i] < sum)//若小边之累和 小于 最长边,则存在闭合多边形
{
cout << i+1;
break;
}
}
}
system("pause");
return 0;
}
VC++6.0编译测试结果:
Solution 2
-
solution1提交不通过,总结经验,发觉时间主要是浪费在了sort函数调用循环嵌套上,经分析只有最大值是有用信息,
所以我们大可不必每次都对b[]数组进行排序,而是选择用b[]数组来记录从开始到对应下标以来所遇到的最大值; -
时间复杂度:O(n) //很清真
#include<iostream>
#include<algorithm>
using namespace std;
#define x 1000000
int a[x], b[x] = { 0 };//大数组全局定义
int main(void)
{
int i, N, sum1, sum2;
cin >> N;
int t = b[0];
for (i = 0; i < N; i++)
{
cin >> a[i];
a[i] > t ? b[i] = a[i], t = b[i] : b[i]=b[i-1]; //b[0]~b[i]对应的存储着从a[0]~a[i]最大的数
}
for (i = 0; i < N; i++) //只是用来测试
{
cout << b[i] << endl;
}
if (N <= 2)
cout << "-1";//小于两条边不能构成封闭多边形
else
{
sum1 = 0;
for (i = 0; i < N; i++)
{
sum1 += a[i];
//cout << "sum = " << sum1 << endl;
sum2 = sum1 + (a[i + 1] - b[i + 1]);
cout << "the max number b[i+1] = " << b[i + 1] << endl;
cout << "sum2 = " << sum2 << endl;
cout << "循环i=" << i << endl;
if (b[i + 1] < sum2)
{
cout << i + 2;
break;
}
if (i == N - 2)
{
cout << "-1";
break;
}
}
}
//system("pause");
return 0;
}
VC++6.0编译测试结果:
Thanks!
/* yzw于2016年12月17日00:35:44 */