Codeforces Round #652 (Div. 2) E. DeadLee(思維題 貪心)

題目

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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章