题意
有 n 份食物,第 i 种食物有 (w_i) 份,有 m 个朋友,每个朋友都有两个爱吃的食物,现在可以决定朋友进来的顺序,当一个朋友进来没吃到自己喜欢的菜的时候,就会吃掉你,问你是否是安全的。如果是,输出朋友进来的顺序。
思考
刚看到这题很熟悉,之前打个人赛的时候做过一道类似的,只不过每份食物都是 1 份。
当时是用的最小生成树,被上题影响了思路,首先在想最小生成树,后来感觉这怎么构造?
优先用份数为 0 的,向外连边,但是如果没有或者所有的菜的份数初始都很大,这该怎么搞?
后来想到用份数足够所有人吃的向外连边,感觉不太行。就GG了。
题解
如果食物 i 足够所有的朋友吃,就把所有想吃食物 i 的朋友放到最后,并且另一种食物的需求量-1,这样就会继续产生新的够吃的食物,如果刚开始所有的食物都不够吃,那么就危险了。
代码
#include <bits/stdc++.h>
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 2e6+10;
vector<pair<int,int> > vec[N];
int w[N], s[N], dis[N], sign[N];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &w[i]);
for(int i = 1; i <= m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
s[u]++, s[v]++;
vec[u].pb(make_pair(v, i));
vec[v].pb(make_pair(u, i));
}
queue<int> q;
for(int i =1 ; i <= n; i++)
{
dis[i] = w[i] - s[i];
if(dis[i] >= 0)
q.push(i);
}
stack<int>ans;
int num = 0;
while(!q.empty())
{
num++;
int now = q.front();
q.pop();
for(auto temp : vec[now])
{
if(!sign[temp.second])
{
dis[temp.first]++;
if(dis[temp.first] == 0){
q.push(temp.first);
}
ans.push(temp.second);
sign[temp.second]=1;
}
}
}
if(num != n)
printf("DEAD
");
else
{
printf("ALIVE
");
while(!ans.empty())
{
printf("%d ", ans.top());
ans.pop();
}
}
printf("
");
return 0;
}
/*
3 2
1 1 0
1 2
1 3
*/