codeforces 825 E Minimal Labels

29 篇文章 1 订阅
1 篇文章 0 订阅

Problem

codeforces.com/contest/825/problem/E

Reference

看第 5 条评论

Meaning

给出一个n个结点的DAG,找一个给结点编号的序列,且满足3个条件:

  • 编号为 1~n,每个编号出现且仅出现一次;
  • 如果存在边从 f 指向 t,则结点 f 的编号要小于 t 的编号;
  • 在所有可行的编号序列中,取字典序最小的;

Analysis

第二个条件就像拓扑排序,再要满足足第三个条件,就在拓扑排序时,每次从所有入度为零的点中,找出最小的点并给它当前可用的最小的编号。
然而,这样做是错的。
比如样例:

---Input---
6 5
6 2
5 2
2 1
4 3
3 1
---Outpuut---
6 3 5 4 1 2

之前像上面那样写(有点像贪心),结果是:6 5 2 1 3 4
可能要先给某些大的点分配小的编号来“解锁”小的点,来取得更小的字典序。
按评论里给出的题解,是要反过来想,存反向边,每次也是考虑入度为零的点,但是选最大的点分配最大的编号。
评论里的证明原文(by krijgertje):

We can prove it by contradiction. Take any graph with the smallest number of nodes for which this algorithm does not give an optimal labeling. The largest label must always be assigned to a node with no outgoing edges, but it can’t be the largest of those nodes (otherwise the algorithm would give the optimal labeling). Lets call the largest node with no outgoing edges x and the node that has the largest label in the optimal labeling y. Then after labeling y with the largest label, the remaining part of the graph is correctly labeled by the algorithm (otherwise we would have a smaller graph for which the algorithm gives an incorrect result). This will first label some nodes greater than x and then it will label x. But we get a better labeling by labeling x with the largest label, y with the next largest and then label the same nodes as before. This is because of the nodes labeled so far y is the smallest node (since y < x and all other labelled nodes are greater than x) and in the partial labeling we have labeled the same nodes using the same labels. So we have a contradiction, which means our assumption was wrong and therefore there is no graph that our algorithm labels incorrectly.

Accepted Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int N = 100000, M = 100000;

vector<int> rev[N+1]; // reverse edge
int deg[N+1]; // degree of vertex
int label[N+1]; // label sequence
priority_queue<int> que;

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    memset(deg, 0, sizeof deg);
    for(int f, t, i=0; i<m; ++i)
    {
        scanf("%d%d", &f, &t);
        rev[t].push_back(f);
        ++deg[f];
    }
    for(int i=1; i<=n; ++i)
        if(!deg[i])
            que.push(i);
    for(int lab=n, t; lab > 0; --lab) // desc
    {
        t = que.top();
        que.pop();
        label[t] = lab;
        for(int i=0; i<rev[t].size(); ++i)
            if(--deg[rev[t][i]] == 0)
                que.push(rev[t][i]);
    }
    for(int i=1; i<=n; ++i)
        printf("%d%c", label[i], i==n?'\n':' ');
    return 0;
}

Wrong Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int N = 100000, M = 100000;

vector<int> g[N+1]; // edge
int deg[N+1];
int label[N+1];
priority_queue<int, vector<int>, greater<int> > que;

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    memset(deg, 0, sizeof deg);
    for(int f, t, i=0; i<m; ++i)
    {
        scanf("%d%d", &f, &t);
        g[f].push_back(t);
        ++deg[t];
    }
    for(int i=1; i<=n; ++i)
        if(!deg[i])
            que.push(i);
    for(int lab=1, t; lab <= n; ++lab) // ascend
    {
        t = que.top();
        que.pop();
        label[t] = lab;
        for(int i=0; i<g[t].size(); ++i)
            if(--deg[g[t][i]] == 0)
                que.push(g[t][i]);
    }
    for(int i=1; i<=n; ++i)
        printf("%d%c", label[i], i==n?'\n':' ');
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值