题意:
有 n 道菜,每道菜的数量为a(i) ,现在有m个人,每个人都有爱吃的两道菜x和y ,当第 i 个人来之后,会吃掉x和y各一份,如果x没有了的话,那么他只会选择吃掉一份y ,没有y同理,但是如果x和y同时没有的话,就不合法。
问是否存在一种序列,使得按照序列顺序,每个人都能吃到菜。如果有,则输出一个合法序列。
数据范围:n<=2e5
解法:
统计每种菜的需求数sum(i),
1.如果sum(x)<=a(y),那么每个选择这个菜的人都能吃到,贪心的将他们放在序列的最后,
2.并假设他们喜欢的另一种食物y吃不到(sum(y)-=1,给其他人留了吃y的机会),然后跳转至1判断y重复操作
实现方法是对每种菜进行拓扑排序,先将sum(i)<=a(i)的菜入队,
当队列不为空的时候:
取出队头菜x,将所有选择菜x的人(x,y)丢到答案尾部,同时sum(y)-=1,如果sum(y)<=a(y),那么y入队。
记得开个标记数组保证每个点只入队一次
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
vector<pair<int,int> >g[maxm];
int mark[maxm];
int mark_idx[maxm];
int sum[maxm];
int a[maxm];
int n,m;
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
int x,y;cin>>x>>y;
sum[x]++;sum[y]++;
g[y].push_back({x,i});
g[x].push_back({y,i});
}
stack<int>ans;
queue<int>q;
for(int i=1;i<=n;i++){
if(sum[i]<=a[i]){
mark[i]=1;
q.push(i);
}
}
while(!q.empty()){
int x=q.front();q.pop();
for(auto i:g[x]){
if(!mark_idx[i.second]){
mark_idx[i.second]=1;
ans.push(i.second);
}
if(mark[i.first])continue;
sum[i.first]--;
if(sum[i.first]<=a[i.first]){
mark[i.first]=1;
q.push(i.first);
}
}
}
if(ans.size()==m){
puts("ALIVE");
while(!ans.empty()){
cout<<ans.top()<<' ';
ans.pop();
}
}else{
puts("DEAD");
}
return 0;
}