ZCMU1206之种树问题

【once分析】 初步判别这道题是求最优化问题,那么可以从动态规划和贪心算法这两方面去思考。

【twice分析】这是一个加了约束条件的贪心算法,我们在加上了一个位置的值后就不能再加上相邻位置的值。而我们又无法判断究竟是两边相加的大还是中间单个位置的大,这就需要一个方法去解决。

【解决方案】1、首先我们确定我们存放这些数据的容器是一个优先队列,该队列中的优先级我们确定是从数字的从大到小;2、其次我们确定位置之间的相邻关系,这个我们可以用pre[x]和next[x]去存放每个x的前一个元素位置和后一个元素位置,3、在m次循环中,我们每次将优先级最高的元素取出,记为temp,然后把他的值加到ans中,然后给这个元素赋上新值,这个新值我们从存放位置的美观的的数组中去寻找(直接用索引找方便,如果在队列中找他相邻的位置的值很麻烦),a[temp.pos]=a[pre[temp.pos]]+a[next[temp.pos]]-a[temp.pos];这样这个新值就是前一个元素加后一个元素减去当前元素的值了。我们再将这个元素的两个相邻元素种上草莓,如果下一次从队列中去除的是这两个相邻元素,那直接给删了,如果取不到,那也无伤大雅。最后再将这个新元素加入到队列中去。

下面给出代码:

#include<iostream>
#include<queue>
#include<cstdio>

using namespace std;

int a[20000],pre[20000],next[20000];
struct node{
	int val;
	int pos;
	bool operator < (const node &x)const{
		return val<x.val;
	}
}; 
bool tf[20000];

void del(int x){
	tf[x] = 1;
	next[pre[x]] = next[x];
	pre[next[x]] = pre[x];
	next[x] = 0;pre[x] = 0;
}//删除该元素

priority_queue<node>q;
int main(){
	int n,i,m,ans=0;
	node temp;//临时节点
	cin>>n>>m;
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	if(n/2<m) cout<<"Error!";
	else{
		for(i=2;i<=n;i++) pre[i] = i-1;pre[1] = n;
		for(i=1;i<n;i++) next[i] = i+1;next[n] = 1;
		for(i=1;i<=n;i++) q.push((node){a[i],i});
		for(i=1;i<=m;i++){
			while(tf[q.top().pos])	q.pop();//当被标记为1时就删除该元素
			temp = q.top();q.pop();
			ans += temp.val;
			int z1 = pre[temp.pos],z2 = next[temp.pos];
			a[temp.pos] = a[z1]+a[z2]-a[temp.pos];//在数组a中去索引值
			del(z1),del(z2);//给temp元素前后相邻两个元素种上草莓,下次遍历到直接删掉,不遍
// 历到就不管他,然后这两个元素的前元素和后元素和temp建立pre、next关系
			q.push((node){a[temp.pos],temp.pos});//把新元素插入队列当中
		}
		cout<<ans<<endl;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值