題目
n(n<=1e5)種菜,m(m<=2e5)個朋友,第i種菜有wi(0<=wi<=1e6)盤
每個朋友有兩盤菜的喜好,x或y,他會隨機挑至少一盤當前有的菜然後喫掉
可以理解爲有兩盤喫兩盤,有一盤只吃一盤,
特別的,如果都沒有,他會把主人喫掉23333
請主人合理地分配朋友就餐順序,使得主人不會被喫掉
如果一定會被喫掉,輸出DEAD;否則輸出ALIVE,及m位朋友的就餐順序
思路來源
B站博主zbw講解、粉兔代碼
題解
對n種菜分開考慮,如果存在第i種菜被集合S的朋友喜愛且均夠喫,
即喜愛i種菜的人有bi個人,當前有ai盤菜,ai>=bi
那麼可以把這bi個人留到最後來分第i種菜,並撤掉這盤菜,
這樣這bi個人都分到了菜,且不會影響到不喫這盤菜的人,
並使其他菜有所剩餘,使方案可能更優
特別地,如果對於所有i,ai<bi,則不妨設排列中最後一個人喜好爲(x,y)
由於ax<=bx-1,ay<=by-1,前n-1個人的需求就會把x、y這兩種菜喫完
導致最後一個人沒菜喫,從而無解
可以把菜加到刪的次序的末尾並更新其他菜這種操作,
視爲類似拓撲排序刪掉入度爲0並更新其他入度的操作,
於是構造好這個刪菜倒序序列後,從後往前遍歷,
每個客人保證在自己只剩一盤喜歡的菜時,再喫掉這盤
代碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
int n,m,x,y,a[N],b[N],del[N];
vector<P>g[N];
int q[N],r;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
}
for(int i=1;i<=m;++i){
scanf("%d%d",&x,&y);
b[x]++;b[y]++;
g[x].pb(P(y,i));
g[y].pb(P(x,i));
}
for(int i=1;i<=n;++i){
if(a[i]>=b[i]){
q[r++]=i;
}
}
for(int l=0;l<r;++l){
int x=q[l];
del[x]=l;
for(P y:g[x]){
int oth=y.fi;
if(a[oth]>=b[oth])continue;
if(--b[oth]==a[oth]){
q[r++]=oth;
}
}
}
if(r!=n){
puts("DEAD");
return 0;
}
puts("ALIVE");
for(int i=n-1;i>=0;--i){
int x=q[i];
for(P y:g[x]){
if(del[y.fi]>i){
printf("%d ",y.se);
}
}
}
return 0;
}