CodeForces 1369E. DeadLee

题意:这里有n种类型不同的食物,还有m个Lee的朋友。Lee有wi盘第i种类型的食物,并且每个朋友都有两种喜欢的类型的食物,第i个朋友喜欢xi和yi类型的食物。Lee将会按顺序叫他的每一个朋友过来吃食物,他会吃这两种食物的一盘,如果只存在一种他喜欢的食物,他会吃掉这种食物的一盘,如果都没有,他会吃了Lee,输出DEAD,否则输出ALIVE,并且输出吃的顺序。

分析:吃的过程存在顺序,说明可能是一种拓扑关系,表示我们可以尝试使用图论的算法。前面的状态会影响后面的状态,因此我们可以先看看能不能采用贪心,对于每种食物的需求量s[i],如果s[i] <= w[i],说明这个食物的分量很足,我们可以放到后面吃,这样是一个不错的决策。比如说我们放到后面吃的话,那么这个食物在前面被人吃了话,比如前面一个人会吃一种食物,顺带把这个食物也吃了,那么后面的人可能只能吃一种的话,那么可能不会产生吃失败的场面,那么它被放在后面可能还会剩很多食物。因此,我们可以用拓扑排序,把那些分量很足的食物,即w[i] >= s[i]的食物入队,当一个食物出队的时候,我们就标记吃这个食物的人已经吃过,并放进答案数组,最后还要把数组翻转一下,因为我们是从后往前拓扑的。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
using PII = pair<int, int>;
const int N = 100005;
const int M = 200005;
int w[N], s[N];
int q[M];

vector<PII> e[N];
//标记删除的点
bool st[M];

int main()
{
    //食物的类型数量,Lee的朋友数量
    int n, m;
    scanf("%d%d", &n, &m);
    
    //每种类型的食物数量
    for(int i = 0; i < n; ++i)
    {
        scanf("%d", &w[i]);
    }

    //memset(h, -1, sizeof h);
    for(int i = 0; i < m; ++i)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        --u, --v;
        e[u].push_back({v, i});
        e[v].push_back({u, i});
        ++s[u], ++s[v];
    }

    int hh = 0, tt = -1;

    //最后吃需求量比补给量少的食物,会对前面的吃食产生良好的影响
    for(int i = 0; i < n; ++i)
        if(w[i] >= s[i])
            q[++tt] = i;

    vector<int> res;

    while(hh <= tt)
    {
        int u = q[tt--];
        for(auto item : e[u])
        {
            int v = item.first, i = item.second;
            if(st[i]) continue;
            st[i] = true;
            res.push_back(i);
            if(--s[v] == w[v])
                q[++tt] = v;
        }

    }

    if(res.size() < m)
    {
        puts("DEAD");
        return 0;
    }

    puts("ALIVE");

    reverse(res.begin(), res.end());

    for(int i = 0; i < res.size(); ++i)
        printf("%d ", res[i] + 1);

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/pixel-Teee/p/13210524.html