题目
思路
唯一可能导致顾客愤怒的菜品,一定供不应求。倘若该菜品的数量足够每个喜欢它的人拿一份,那么所有喜欢它的人都至少有这个菜可以拿,我们便安排这些人最后取。或者说,我们忽略他们,因为他们不会骂骂咧咧地吃掉厨师,尽管吃饭的时候无论说话还是骂人都不大清楚。
忽略他们之后,剩下的菜品就可以继续上面的操作了,因为那些友善的人已经被忽略了。
反复执行,最后还是所有的菜品都不够用,那么厨师死定了。原因是,最后一个人一定拿不到菜,否则存在一道菜是数量充足的。
只需要用类似拓扑排序的方法删掉每一道菜即可。人的顺序就是删掉顺序的逆序。复杂度 O ( n + m ) \mathcal O(n+m) O(n+m) 。
代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
template < typename T >
void getMax(T&a,const T&b){if(a<b)a=b;}
template < typename T >
void getMin(T&a,const T&b){if(b<a)a=b;}
const int MaxN = 100005;
int a[MaxN], w[MaxN], n, m;
struct Edge{
int to, nxt;
Edge(int T=0,int N=0){
to = T, nxt = N;
}
} edge[MaxN<<2];
int head[MaxN], cntEdge;
void addEdge(int a,int b){
edge[cntEdge] = Edge(b,head[a]);
head[a] = cntEdge ++;
edge[cntEdge] = Edge(a,head[b]);
head[b] = cntEdge ++;
}
bool died[MaxN], done[MaxN<<1];
vector< int > v, ans;
int main(){
n = readint(), m = readint();
for(int i=1; i<=n; ++i)
w[i] = readint();
for(int i=1; i<=n; ++i)
head[i] = -1;
for(int i=1,a,b; i<=m; ++i){
a = readint(), b = readint();
addEdge(a,b); -- w[a], -- w[b];
}
for(int i=1; i<=n; ++i)
if(w[i] >= 0){
v.push_back(i);
died[i] = true;
}
while(!v.empty()){
int t = v.back(); v.pop_back();
for(int i=head[t]; ~i; i=edge[i].nxt){
++ w[edge[i].to];
if(!done[(i>>1)+1])
ans.push_back((i>>1)+1);
done[(i>>1)+1] = true;
if(died[edge[i].to]) continue;
if(w[edge[i].to] >= 0){
died[edge[i].to] = true;
v.push_back(edge[i].to);
}
}
}
for(int i=1; i<=n; ++i)
if(!died[i]){
puts("DEAD");
return 0;
}
puts("ALIVE");
while(!ans.empty()){
printf("%d ",ans.back());
ans.pop_back();
}
return 0;
}