Codeforces Round #582 (Div. 3)_tarjan算法

题目链接:https://codeforces.com/contest/1213/problem/F

解题思路:
直接让a[i] 指向 a[i + 1], 表示的意思是字母大小小的指向大的;所以我们形成环的所有下标的位置必须是相同的字母,所以我们可以直接使用 tarjan算法,判断环的个数ans, 如果ans < k,则直接输出NO,否则输出YES。

注意:
题目中要求我们输出的是从1 - n输出对应的字母,而不是按照给出的序列输出对应的字母, 比赛的时候,我就是因为输出弄错了没过这道题。

代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <stack>

using namespace std;

const int N = 2e5 + 10, M = 6e5 + 5;

int n, k, num, cnt;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], c[N], ins[N], a[N];
stack<int> st;
vector<int> ssc[N];
char str[N];

inline void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

inline void tarjan(int x) {
	dfn[x] = low[x] = ++ num;
	st.push(x); ins[x] = 1;
	
	for(int i = h[x]; i + 1; i = ne[i]) {
		int v = e[i];
		if(!dfn[v]) {
			tarjan(v);
			low[x] = min(low[x], low[v]);
		} else if(ins[v]) {
			low[x] = min(low[x], dfn[v]);
		}
	}
	
	if(low[x] == dfn[x]) {
		++ cnt; int y;
		do {
			y = st.top(); st.pop(); ins[y] = 0;
			c[y] = cnt; ssc[cnt].push_back(y);
		} while(x != y);
	}
}

int main(void) {
//	freopen("in.txt", "r", stdin);
	scanf("%d%d", &n, &k);
	memset(h, -1, sizeof h);

	for(int i = 1; i <= n; i ++) {
		scanf("%d", &a[i]);
		if(i > 1) add(a[i - 1], a[i]);
	} 
	for(int i = 1; i <= n; i ++) {
		scanf("%d", &a[i]);
		if(i > 1) add(a[i - 1], a[i]);
	}

	for(int i = 1; i <= n; i ++) 
		if(!dfn[i]) tarjan(i);

	if(cnt < k) puts("NO");
	else {
		puts("YES");
		char tmp = 'a';
		int pre;
		for(int i = 1; i <= n; i ++) {
			if(i == 1) {
				str[a[i]] = tmp;
				pre = c[a[i]];
			} else {
				if(pre == c[a[i]]) str[a[i]] = tmp;
				else {
					if(tmp < 'z') tmp += 1;
					str[a[i]] = tmp;
					pre = c[a[i]];
				}
			}
		} 

		for(int i = 1; i <= n; i ++)
			printf("%c", str[i]);
		puts("");
	}
	
	return 0;
}


总结:审题要仔细,在动手之前起码得把要输出什么弄清楚。
注意 tarjan算法中直接从1 - n去扫面。

发布了136 篇原创文章 · 获赞 0 · 访问量 2990

猜你喜欢

转载自blog.csdn.net/weixin_42596275/article/details/102325785