Codeforces 875C National Property(拓扑排序)

题目链接  National Property

给定n个单词,字符集为m

现在我们可以把其中某些字母变成大写的。大写字母字典序大于小写字母。

问是否存在一种方案使得给定的n个单词字典序不下降。

首先判断是否存在相邻的两个单词,后一个是前一个的前缀。(两者不相等)

如果出现这种情况则直接输出无解。

建立起点s和终点t。每次扫描相邻的两个单词,找到他们第一个不相等的字母的位置。

和s相连的字母必须改成大写,和t相连的字母必须不能改成大写。

设前面那个单词的这个位置的字母为a, 后面的为b

如果a > b那么s到a之间连边,b到t之间连边(a一定要改成大写,b一定不能改成大写,否则就不成立了)

如果a < b那么b到a连一条有向边(如果a改成大写了那b更要改成大写了,因为这个关系的存在,b的字典序一定要大于a)

无解的判定:如果从s出发能走到t那么存在一个字母他必须改成大写也必须不能改成大写,矛盾。

最后把和s相连的那些字母都改成大写即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

const int N = 1e5 + 10;

int a[N], b[N];
int n, m;
int s, t, k, ret;
int vis[N];
vector <int> v[N];
vector <int> ans;

void dfs(int x){
	if (x == t){ puts("No"); exit(0);}
	vis[x] = 1;
	ans.push_back(x);
	for (auto u : v[x]) if (!vis[u]) dfs(u);
}

int main(){

	scanf("%d%d", &n, &m);
	s = m + 1, t = m + 2; 
	rep(i, 1, n){
		scanf("%d", b);
		rep(j, 1, b[0]) scanf("%d", b + j);
		if (i == 1) rep(j, 0, b[0]) a[j] = b[j];
		for (k = 1; k <= a[0] && k <= b[0] && a[k] == b[k]; ) ++k;
		if (k <= a[0] && k > b[0]) return 0 * puts("No");
		else if (k <= a[0] && k <= b[0]){
			if (a[k] > b[k]){
				v[s].push_back(a[k]);
				v[b[k]].push_back(t);
			}
			else v[b[k]].push_back(a[k]);
		}
		rep(j, 0, b[0]) a[j] = b[j];
	}

	dfs(s);
	printf("Yes
%d
", (ret = ans.size()) - 1);
	rep(i, 1, ret - 1) printf("%d ", ans[i]);
	return 0 * putchar(10);
}
原文地址:https://www.cnblogs.com/cxhscst2/p/7781078.html