CF1369E- DeadLee
题意:
\(Lee\) 的厨房中有 \(n\) 道菜,每道菜的数量为 \(w[i]\) ,现在 \(Lee\) 邀请 \(m\) 个朋友,每个朋友都有最爱吃的两道菜 \(x[i]\) 和 \(y[i]\) ,当朋友 \(i\) 来到 \(Lee\) 家后,会选择吃掉 \(x[i]\) 和 \(y[i]\) 各一份,如果 \(x[i]\) 没有了的话,那么他只会选择吃掉一份 \(y[i]\),如果 \(y[i]\) 没有了的话同理,但是如果 \(x[i]\) 和 \(y[i]\) 同时没有的话,这个朋友就会吃掉 \(Lee\),问 \(Lee\) 能否安排一个合适的顺序以保证存活,输出这个顺序。
分析:
记 \(sum[i]\) 表示要吃第 \(i\) 种菜的人数,当 \(sum[i]\leq w[i]\),表示这 \(sum[i]\) 个人都可以吃菜。那么,就可以把这些人,放在后面来吃。如果 \(\forall sum[i]\),都有 \(sum[i]>w[i]\),则表示没有解。因此,从满足 \(sum[i]\leq w[i]\) 的食物出发,类似于拓扑排序不断向队列里面加满足要求的食物,直到可以吃到食物的人数为 \(m\)。
代码:
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=2e5+5;
typedef pair<int,int>pii;
int w[N],sum[N];
vector<pii>food[N];
int n,m;
queue<int>que;
stack<int>ans;
bool vis[N];
bool solve()
{
for(int i=1;i<=n;i++)
{
if(sum[i]<=w[i])
que.push(i);
}
while(!que.empty())
{
int t=que.front();
que.pop();
for(int i=0;i<food[t].size();i++)
{
int a=food[t][i].first;
int b=food[t][i].second;
if(vis[b]) continue;
ans.push(b);
vis[b]=1;
if(--sum[a]<=w[a]) que.push(a);
}
}
return ans.size()==m;
}
int main()
{
int x,y;
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,&y);
sum[x]++,sum[y]++;
food[x].pb(make_pair(y,i));
food[y].pb(make_pair(x,i));
}
if(solve())
{
printf("ALIVE\n");
while(!ans.empty())
{
int t=ans.top();
ans.pop();
printf("%d%c",t,ans.empty()?'\n':' ');
}
}
else printf("DEAD\n");
return 0;
}