[NBOJ0063][高才生]

[题目要求]

http://acm.bupt.edu.cn/onlinejudge/newoj/showProblem/show_problem.php?problem_id=63

[题目涉及的相关理论与算法]
vector排序,重载运算符。
递推关系式

[题目中需要注意的地方]
注意坐标允许输入0。
两次排序的输入顺序都是以房子号位基准,而计算最小路程需要将坐标的位置排序。

[思路过程]
1,建立一个数据结构的vector容器,然后重载排序,按照坐标值排序,同时带上其是否可以建立基站的标记。
2,观察并找出递推关系,即,如果将基站从一个点i移到他后面的一个点,此时,我们需要多铺设前面i个点到i+1点的距离,同时也可以省去后面n-i个i+1点到i的距离。遍历一遍即可得到结果。

[代码]

#include<iostream>
#include<vector>
#include<algorithm>
int const MAX=1000000;
using namespace std;
void caseSolve(int n)
{
	vector<int> loc;
	bool will[MAX];
	int *p_result = new int[n];			//储存每一个坐标的搭建长度。
	int temp=0;
	for(int i=0;i<n;i++)
	{
		int pos;
		cin>>pos;
		loc.push_back(pos);
		temp += pos;		//temp此时用来储存所有的坐标结点的和,即再减去重复的第一个坐标的值就是基站建立在第一个房子的搭建长度。	
	}	
	for(int i=0;i<n;i++)
		cin>>will[loc[i]];
	sort(loc.begin(),loc.end());//容器的带参数排序。默认是升序。
	p_result[0]=temp-n*loc[0];	//如上所述,减去重复n编的第一个坐标,就得到基站在开头的长度。
	for(int i=1;i<n;i++)
	{
		int x = loc[i]-loc[i-1];
		p_result[i]= p_result[i-1]+i*x-(n-i)*x;//核心算法,我们在得到前一个结点的搭建长度后,可以找到和此时的结点的长度的关系。
	}
	for(int i=0;i<n;i++)
	{
		if(will[loc[i]] == false) continue;
		if(p_result[i] < temp) temp = p_result[i];//遍历一遍,如果此用户愿意,那么比较这个用户搭建的长度是不是最小的,如果是,记录下结果。
	}
	cout<<temp<<endl;
	delete [] p_result;
}
int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);	
	int n;
	cin >> n;
	while(n != 0)
	{
		caseSolve(n);
		cin>>n;
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}
[尾声]
做得相当不顺利,一开始以为坐标是房子的序号范围内。。结果可想可知,后面是算法不好,LTE了,暴力求解,排序之后,从意愿的数组中从中间向两边查找第1个不是零的。这样每次需要一次查找和计算,结果就是LTE了。结果一上午就耗在这了。。后面才想到每一个点之间是有联系的,所以前后遍历即可得到结果,所以很划算的,这样终于AC了。。。
另外,今天值得庆幸的是我的排名居然进前100了。。只做了18题就进了前100,可见北邮的大牛都pku去了。。这里好冷清!哎~  网上查了查,这题都说是水题,可是把我整了几乎一上午加半个下午。。失败。。。听到一首好歌,送给大家。。。



你可能感兴趣的:(ACM,vector排序,高才生)