CF Round#652 E.DeadLee(贪心;构造)

CF Round#652 E.DeadLee

题目介绍

链接: 传送门.
Lee有n个食物,第i个食物有wi份;他还有n个朋友,第i个朋友有两种不同的喜爱食物xi和yi。每个朋友进入厨房时,若两种喜爱的食物都有,则两种都吃掉(try to eat one plate of each of his favorite food types);否则若有一种则吃这剩下的一种;否则他会吃掉Lee。
问以怎样的顺序安排朋友进入,能够使Lee不被吃掉。

题解

考察算法:贪心;构造;(拓扑排序)
注意题意:若有两盘喜爱的食物则都吃;否则若有任一种剩余则只吃该种。
对每个食物有容量w[i],设需求量need[i]为喜欢吃它的人数,
若对所有食物i,w[i]<need[i]则无解。

(1) 对w[i]>=need[i]的食物放入队列中。
(2) 若w[i]>=need[i],则喜欢吃第i种食物的人都可以放到最后,
且这样的人对另一种食物无影响,则另一种食物的需求量可以减少,
(3) 当某一种食物的w[i]初次大于等于need[i],可将其加入操作队列;
重复以上操作,若最终排列的人数等于m,则成立,倒序输出答案即可;否则不成

代码

#include<cstdio>
#include<queue>
#include<vector>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;
const int maxn=2e5+5;
const int base=1e9+7;
int w[maxn],need[maxn],x[maxn],y[maxn],ans[maxn];
bool in_ans[maxn];
vector<int> vec[maxn];
queue<int> que;

int main(){
	memset(in_ans,false,sizeof(in_ans));
	int n,m,cnt=0; scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x[i],&y[i]);
		w[x[i]]--; w[y[i]]--;
		vec[x[i]].push_back(i);
		vec[y[i]].push_back(i);
	}
	for(int i=1;i<=n;i++){
		if(w[i]>=0) que.push(i);
	}
	
	int k,size,u,another;
//	每种食物进队一次,friend遍历2遍O(n+m) 
	while(!que.empty()){
		k=que.front(); que.pop();
		size=vec[k].size();
		for(int i=0;i<size;i++){
//			friend编号;排到末尾 
			u=vec[k][i];         
			if(!in_ans[u]) ans[++cnt]=u,in_ans[u]=true;
//			另一种喜爱的食物 
			if(x[u]!=k) another=x[u];
			else another=y[u];
			w[another]++;
			if(w[another]==0) que.push(another);
		}
	}
	if(cnt<m) printf("DEAD\n");
	else{
		printf("ALIVE\n");
		for(int i=cnt;i>=1;i--) printf("%d ",ans[i]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值