[codeforces 1271D] Portals 反悔贪心算法

[codeforces 1271D] Portals   反悔贪心算法

总目录详见https://blog.csdn.net/mrcrack/article/details/103564004

在线测评地址http://codeforces.com/contest/1271/problem/D

ProblemLangVerdictTimeMemory
1271D - Portals GNU C++11Accepted78 ms100 KB

//此文https://blog.csdn.net/Missing_Cloud/article/details/103581785思路不错,摘抄如下
/*
之前的做法过于混乱(甚至我自己都觉得像是瞎蒙的),因此借鉴了其他神犇的题解仔细思考后发现可以使用反悔型贪心来做这道题。
思路为:
一路扫过去,每次都假定留守所有可留守的点,发现当前的士兵不够则从已留守的点中选取权值最小的放弃留守。
依然是基于 靠后留守更优 策略,预处理出每个点可留守的集合,遍历到该点直接将可留守的全部push到已留守集合中,再遍历下一个点。 在遍历点过程中发现士兵不够,pop已留守集合,如果pop空了还不够,说明游戏失败。
代码一起放到后面了。自我感觉注释够详细了。
*/
//样例通过,提交AC.2019-12-22 16:03

#include <cstdio>
#include <queue>
#include <vector>
#define maxn 5010
using namespace std;
int a[maxn],b[maxn],c[maxn],last[maxn],head[maxn],tot=0;//last[i]记录i最后能在哪里被留守,//head[i]存储该点可以向前留守什么点
int N,M,K;
priority_queue<int,vector<int>,greater<int> > q;
struct node{
	int to,next;
}e[maxn];
void add_edge(int u,int v){
	tot++,e[tot].to=v,e[tot].next=head[u],head[u]=tot;
}
void init(){
	int i,u,v;
	scanf("%d%d%d",&N,&M,&K);
	for(i=1;i<=N;i++)scanf("%d%d%d",&a[i],&b[i],&c[i]),last[i]=i;
	for(i=1;i<=M;i++)scanf("%d%d",&u,&v),last[v]=last[v]>u?last[v]:u;//last[v]取更大者,因为越后留守一定越好//此处错写for(i=i;i<=M;i++)scanf("%d%d",&u,&v),last[v]=last[v]>u?last[v]:u;成查了会
	for(i=1;i<=N;i++)add_edge(last[i],i);//此处错写成for(i=1;i<=N;i++)add_edge(last[v],v);造成了linux下的段错误
}
int main(){
	int i,ed,v,ans=0;
	init();
	for(i=1;i<=N;i++){
		while(K<a[i]&&!q.empty())K++,q.pop();//不够的话,从已留守的城堡中取出权值最小的放弃
		if(K<a[i]){printf("-1\n");return 0;}//如果取完还是不够,那没办法了,输出-1
		K+=b[i];//占领当前点
		for(ed=head[i];ed;ed=e[ed].next)//往前留守,这里不用考虑当前点,因为当前点要么也在vector中,要么在后面可以被留守
			v=e[ed].to,q.push(c[v]),K--;//可以直接全部push到留守集合中,等后面再反悔,不用考虑会不会让k<0
	}
	while(K<0&&!q.empty())K++,q.pop();//最后一步后还要判断k是否大于0进行一次反悔//此处错写成while(K<a[i]&&!q.empty())K++,q.pop();
	if(K<0){printf("-1\n");return 0;}//此处错写成if(K<a[i]){printf("-1\n");return 0;}
	while(!q.empty())ans+=q.top(),q.pop();//统计已留守点的权值和
	printf("%d\n",ans);
	return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值