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

 

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