题解
题意 :
给出数据 A , B , 代表 A 赢了 B , 给出多组数据 , 求最终的排名 , 名次相同 编号小 的优先输出 .
思路 :
由拓扑序列的性质可知 , 图中存在顶点 A 到 顶点 B 的边 , 则说明 A 出现在 B 前面 , 也就是说 A 赢了 B . 如此 , 跑一边拓扑排序 , 按顺序遍历删除顶点 , 同时将删除的顶点存入数组 , 最后输出即可 .
代码
- 题目数据量比较小 , 直接用矩阵存图 , 如果数据量很大 , 需要用邻接表
- 这是最朴素的拓扑 , 可以用队列优化一下 , 初始化将所有入度为零的点加入队列 , 每次出队一个 , 删边删顶点
类封装版本, 链式前向星 + 用优先队列优化
#include <bits/stdc++.h>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
typedef long long ll;
class TopologicalSort_AdjicencyList {
public:
static const int MAXN = 5e2+10 ;
static const int MAXM = 2e3+10;
int n, cntOfVertex;
struct EDGE {
int v, to;
}e[MAXM];
int head[MAXM], cnt;
inline void add ( int u, int v ) {
e[cnt].v = v, e[cnt].to = head[u]; head[u] = cnt++; deg[v]++;
}
int deg[MAXN], ans[MAXN];
TopologicalSort_AdjicencyList ( ) { };
TopologicalSort_AdjicencyList ( int _n ) : n( _n ) { };
void ini ( int n ) {
this->n = n;
cntOfVertex = 0;
cnt = 0;
memset( head, -1, sizeof(head) );
memset( deg , 0 , sizeof(deg) ) ;
memset( ans , 0 , sizeof(ans) ) ;
}
void run ( ) {
cntOfVertex = 0;
priority_queue<int, vector<int>, greater<int> >q; //当要求编号小的优先输出时用优先队列存储点
while ( !q.empty() ) q.pop();
for ( int i = 1; i <= n; ++i )
if ( !deg[i] )
q.push( i );
while ( !q.empty() ) {
int u = q.top();
q.pop();
ans[cntOfVertex++] = u;
for ( int k = head[u]; k != -1; k = e[k].to ) {
int v = e[k].v;
deg[v]--;
if ( !deg[v] ) q.push( v );
}
}
std::cout << ans[0];
for ( int i = 1 ; i < cntOfVertex ; ++i ) {
std::cout << " " << ans[i] ;
}
std::cout << std::endl ;
}
}tp;
int main ( ) { // freopen( "F:\\in\\out\\1.txt" , "r" , stdin ); // freopen( "F:\\in\\out\\2.txt" , "w" , stdout );
int n, q,
u, v;
while ( cin >> n >> q ) {
tp.ini( n );
while ( q-- ) {
cin >> u >> v ;
tp.add( u, v );
}
tp.run() ;
}
return 0 ;
}
朴素版本
#include <bits/stdc++.h>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
typedef long long ll;
const int MAXN = 5e2+10 ;
int n, q,
u, v;
int graph[MAXN][MAXN], deg[MAXN], ans[MAXN];
void topo ( ) {
for ( int i = 1 ; i <= n ; ++i ) {
for ( int j = 1 ; j <= n ; ++j ) { // 找入度为 0 的顶点
if ( !deg[j] ) {
deg[j]-- ; // 删顶点
ans[i] = j ;
for ( int k = 1 ; k <= n ; ++k ) {
if ( graph[j][k] ) {
graph[j][k] = 0 ; // 删边
deg[k]-- ;
}
}
break ; // 不要忘记终止 , 因为找的是入度为 0 的点 , 不终止 , ++j 以后 , j 就不一定是入度为 0 的点了
}
}
}
}
int main ( ) { // freopen( "F:\\in\\match.txt" , "r" , stdin ) ;
while ( cin >> n >> q ) {
memset( graph , 0 , sizeof(graph) ) ;
memset( deg , 0 , sizeof(deg) ) ;
memset( ans , 0 , sizeof(ans) ) ;
while ( q-- ) {
cin >> u >> v ;
if ( !graph[u][v] ) { // 处理重边
graph[u][v] = 1 ;
deg[v]++ ;
}
}
topo() ;
for ( int i = 1 ; i <= n ; ++i ) {
if ( i==1 ) cout << ans[i] ;
else cout << " " << ans[i] ;
}
cout << endl ;
}
return 0 ;
}
题目
Sample Input
4 3
1 2
2 3
4 3
Sample Output
1 2 4 3