2016 UESTC 第八届ACM趣味程序设计竞赛第三场(正式赛)(比赛场)B - 保护果实

——引言:这是我的第一篇博客文章 记录时间于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(N1,000,000) N(N≤1,000,000)

第二行有N个数,第i个数表示第i块栅栏的长度 ai ai  (aiint) (ai之和不会超过int的上界)

Output

输出一个数,表示最少需要的栅栏数,如果无解输出-1.

Sample input and output

Sample Input Sample Output
3
3 4 5
3

Source

Solution 1

  1. 理解题意,只能按给定的顺序从前往后顺序进行购买;
  2. 要围成一个栅栏(多边形),排除1,2两条边无法相围形成多边形的这种情况;
    其余n>=3,只要最长的一条边小于剩余小边之和就可以构成多边形(基于两点之间直线最短原理);
  3. 使用a[]数组记录输入数据,拷贝的b数组用sort排序,使得b数组最后一个数始终最大;
  4. 算法时间复杂度: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

  1. solution1提交不通过,总结经验,发觉时间主要是浪费在了sort函数调用循环嵌套上,经分析只有最大值是有用信息,
    所以我们大可不必每次都对b[]数组进行排序,而是选择用b[]数组来记录从开始到对应下标以来所遇到的最大值;

  2. 时间复杂度: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!

/* yzw2016121700:35:44 */



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值