Problem

codeforces.com/contest/825/problem/E

Meaning

• 编号为 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

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