来源:长沙理工大学2018区域赛个人选拔赛1
题目:
描述:
在一种竞赛中,题目往往是成套出现的。一道基础题,稍加改动就会使难度上升几个档次。
现在有n道题目,编号为1~n;给出了m个二元组,每个二元组 <a,b> < a , b > 表示 b题目是a题目的加强版,每个题目可能会有多个加强版,加强版的题目也可能会有加强版。
现在要将这n道题目放组成一场比赛,出于人文关怀方面的考虑,一道题目的简单版本必须放在其所有加强版的前面。
例如b是a的加强版,c是b的加强版 那么c在比赛中的题号必须大于a和b的题号,b的题号也必须大于a的题号
你需要做得,是输出一个长度为n的序列A,A[i] 表示编号为i的题目在比赛中的题号。
符合要求的答案很多,出题人并不想写spj,所以请输出字典序最小的方案。
输入:
第一行为两个数n,m表示有n道题,m个二元组(n,m≤106n,m \leq 10^6n,m≤106)
接下来有m行,每行有两个数a,b 表示 题目b是题目a的加强版(1≤a,b≤n1 \leq a,b \leq n1≤a,b≤n)。
输入保证有解
输出:
按顺序输出每道题在比赛中的题号,要求字典序最小。
样例输入:
5 10
5 2
4 1
2 1
3 4
2 4
3 2
5 4
3 5
3 1
5 1
样例输出:
5 3 1 4 2
题解:
套一个字典序最小的拓扑排序模板就好了
AC代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
using namespace std;
/********************拓扑排序+队列实现****************************/
const int maxv = 1e6 + 10;
const int maxe = 1e6 + 10;
struct Edge {
int to, val, next;
} edge[maxe];
int head[maxe], in[maxe], cnt, TPOindex, TPOQueue[maxv], ans[maxv];
int n, m;
priority_queue<int, vector<int>, greater<int> > pqi;
void Topsort() {
for (int i = 1 ; i <= n ; i++) {
if (in[i] == 0) {
pqi.push(i);
}
}
while (!pqi.empty()) {
int cur = pqi.top();
pqi.pop();
TPOQueue[TPOindex++] = cur;
for (int i = head[cur]; i != -1; i = edge[i].next) {
in[edge[i].to]--;
if (in[edge[i].to] == 0)
pqi.push(edge[i].to);
}
}
}
void addedge(int from, int to) {
TPOindex = 0;
edge[cnt].to = to;
edge[cnt].next = head[from];
head[from] = cnt++;
}
void init() {
cnt = 0;
memset(head, -1, sizeof head);
memset(in, 0, sizeof in);
}
/********************拓扑排序+队列实现****************************/
int main(void) {
init();
int t1, t2;
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
scanf("%d%d", &t1, &t2);
addedge(t1, t2);
in[t2]++;
}
Topsort();
int index = 1;
for (int i = 0; i < TPOindex; i++)
ans[TPOQueue[i]] = index++;
for (int i = 1; i <= n; i++)
printf("%d%c", ans[i], i == n ? '\n' : ' ');
return 0;
}