Codeforces Round #541 (Div. 2) D. Gourmet choice(并查集+拓扑) F. Asya And Kittens(启发式合并+链表)

D. Gourmet choice

题意:给出两个序列 a i a_i b j b_j 的大小关系,问能否恢复这两个序列,如果可以则输出,否则输出 N o No
题解:因为有等于号的存在,所以导致建图会形成环,因此我们考虑用并查集将等于关系的缩成一个点,然后去建图,跑一遍拓扑即可。

代码

#include<bits/stdc++.h>

#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
#define P pair<int,int>
using namespace std;
int a[2010], f[2020], in[2010], ans[2010];
vector<int> E[2010];

int getf(int v) 
{
	if(f[v] == v) return v;
	return f[v] = getf(f[v]);
}

void mrg(int u,int v)
{
	int p = getf(u);
	int q = getf(v);
	if(p != q) f[p] = q;
}

void addEdge(int u,int v)
{
	E[u].push_back(v);
	in[v]++;
}

bool topsort(int n)
{
	queue<P> q;
	for(int i = 1; i <= n; ++i) if(!in[i]) q.push(P(i,1));
	while(!q.empty()) {
		P cur = q.front(); q.pop();
		ans[cur.first] = cur.second;
		for(auto v : E[cur.first]) {
			if(--in[v] == 0) q.push(P(v,cur.second + 1));
		}
	}
	for(int i = 1; i <= n; ++i) {
		if(!(ans[i] = ans[getf(i)])) return 0;
	}
	return 1;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    ios::sync_with_stdio(false); cin.tie(0);
	int n,m;
	for(int i = 0; i < 2010; ++i) f[i] = i;
	cin >> n >> m;
	string s[1020];
	for(int i = 0; i < n; ++i)
		cin >> s[i];
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; j <= m; ++j) {
			if(s[i - 1][j - 1] == '=') mrg(i, n + j);
		}
	}
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; j <= m; ++j) {
			if(s[i - 1][j - 1] == '>') {
				if(getf(i) != getf(n + j)) {
					addEdge(getf(n + j), getf(i));
				}else{
					return cout << "No\n",0;
				}
			}else if(s[i - 1][j - 1] == '<') {
				if(getf(i) != getf(n + j)) {
					addEdge(getf(i), getf(n + j)); 
				}else{
					return cout << "No\n",0;
				}
			}
		}
	}
	if(topsort(n + m)) {
		cout << "Yes" << endl;
		for(int i = 1; i <= n + m; ++i) {
			cout << ans[i] << (((i == n)||(i == n + m)) ? '\n' : ' ');
		}
	}else{
		cout << "No" << endl;
	}
    return 0;
}

F. Asya And Kittens

题意:每次合并相邻的两个集合,然后输出最后的序列。
题解:明显并查集了,但是考虑到每次必须合并的是相邻的两个集合,即有位置关系,需要启发式合并,将集合小的放到集合大的下面,因此我们用链表来维护一个集合,每次合并的时候根据大小将两个链表 s p l i c e splice 连接一下就好了。

代码

#include<bits/stdc++.h>

#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

using namespace std;
const int N = 150100;
int f[N],n;
list<int> lis[N];

int getF(int v)
{
	if(f[v] == v) return f[v];
	return f[v] = getF(f[v]);
}

void merge1(int u,int v)
{
	int t1 = getF(u);
	int t2 = getF(v);
	if(t1 != t2) {
		if(lis[t1].size() > lis[t2].size()) {
			f[t2] = t1;
			lis[t1].splice(lis[t1].end(),lis[t2]);
		}else {
			f[t1] = t2;
			lis[t2].splice(lis[t2].end(),lis[t1]);
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    ios::sync_with_stdio(false); cin.tie(0);
	cin >> n;
	int x,y;
	for(int i = 0; i <= n; ++i) {
		f[i] = i;
		lis[i].push_back(i);
	}
	for(int i = 0; i < n; ++i) {
		cin >> x >> y;
		merge1(x,y);
	}
	
	int rt = getF(1);
	for(auto &v : lis[rt]) {
		cout << v << ' ';
	}
    return 0;
}
发布了219 篇原创文章 · 获赞 23 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Eternally831143/article/details/88076547