1. 程式人生 > 實用技巧 >年功序列 題解

年功序列 題解

年功序列

分析

此題如果沒有Chtholly年紀大了記憶力未必好,如果第\(i\)個序列與前\(i−1\)個序列衝突的話那麼就只需要考慮前\(i−1\)個序列就好了的限制,就會是一道\(topsort\)的板題。

判斷是否有環

建立鄰接表

輸入時前後相連,建立鄰接表,如果無環則會形成一個長鏈。

判環

\(x[1]\)開始判斷,如果有環,就直接退出迴圈。

具體方法
bool check(int x) {
	for (int i = 0; i < G[x].size(); i++) {
		if (vis[G[x][i]] == 1) {//如果已經訪問過,就說明有環存在
			return 0;
		}
		vis[G[x][i]] = 1;
		if (check(G[x][i]) == 0) {
			vis[G[x][i]] = 0;//重置
			return 0;
		}
	}
	vis[x] = 0;//重置
	return 1;
}

實現

#include <cstring>
#include <queue>
#include <vector>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 5;

int n, m, x[MAXN], deg[MAXN], ans[MAXN], cnt;
bool vis[MAXN];

vector<int> G[MAXN];
priority_queue<int, vector<int>, greater<int> > q;

bool check(int x) {
	for (int i = 0; i < G[x].size(); i++) {
		if (vis[G[x][i]] == 1) {
			return 0;
		}
		vis[G[x][i]] = 1;
		if (check(G[x][i]) == 0) {
			vis[G[x][i]] = 0;
			return 0;
		}
	}
	vis[x] = 0;
	return 1;
}

void topsort() {
	for (int i = 1; i <= n; i++) {
		if (deg[i] == 0) {
			q.push(i);
		}
	}
	while (q.size()) {
		int u = q.top();
		q.pop();
		ans[++cnt] = u;
		for (int i = 0; i < G[u].size(); i++) {
			deg[G[u][i]] --;
			if (deg[G[u][i]] == 0) {
				q.push(G[u][i]);
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		printf ("%d ", ans[i]);
	}
}

int main() {
	scanf ("%d %d", &n, &m);
	while (m --) {
		int k;
		scanf ("%d", &k);
		memset(vis, 0, sizeof(vis));
		for (int i = 1; i <= k; i++) {
			scanf ("%d", &x[i]);
			if (i != 1) {
				deg[x[i]] ++;
				G[x[i - 1]].push_back(x[i]);
			}
		}
		vis[x[1]] = 1;
		if (! check(x[1])) {
			for (int i = 2; i <= k; i++) {
				G[x[i - 1]].pop_back();
				deg[x[i]] --;
			}
			break;
		}
	}
	topsort();
	return 0;
}