Codeforces Round #541 (Div. 2) D 并查集 + 拓扑排序

https://codeforces.com/contest/1131/problem/D

题意

给你一个n*m二维偏序表,代表x[i]和y[j]的大小关系,根据表构造大小分别为n,m的x[],y[],使得两个数组中最大的数尽量小

题解

  • 按照偏序表,构造出从小到大的拓扑图
  • 如何解决相等的数的偏序关系?
    • 用并查集缩点后再进行拓扑排序
  • 如何解决最大的数最小?
    • 只需要使得同一层的数相同就行,可以一批处理栈中的元素,对于一批栈中的元素产生的新点,先放进一个容器里,然后等到这批栈清空了,再把这个容器中的点放进栈中

坑点

  • 需要标记已经进栈的并查集,防止同一个并查集重复进栈

代码

#include<bits/stdc++.h>
#define M 4005
using namespace std;
int n,m,i,j,in[M],u,v,c[M],cnt;
char s[M][M];
stack<int>S;
queue<int>Q;
vector<int>g[M];
int fa[M];int fin(int u){return fa[u]==u?u:fa[u]=fin(fa[u]);}
void merge(int u,int v){
	int x=fin(u),y=fin(v);
	if(x!=y)fa[x]=y;
}
int main(){
	cin>>n>>m;
	for(i=1;i<=n+m;i++)fa[i]=i;
	for(i=1;i<=n;i++)scanf("%s",s[i]+1);
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			if(s[i][j]=='='){
				merge(i,j+n);
			}
		}
	}
    for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			u=fin(i);v=fin(j+n);
			if(s[i][j]=='>'){
				in[u]++;g[v].push_back(u);
			}else if(s[i][j]=='<'){
				in[v]++;g[u].push_back(v);
			}
		}
	}
	cnt++;
	for(i=1;i<=n+m;i++){
		u=fin(i);
		if(in[u]==0&&!c[u]){
			S.push(u);
			c[u]=cnt;
		}
	}
    while(!S.empty()||!Q.empty()){
		if(!S.empty()){
		  u=S.top();S.pop();
		  for(i=0;i<g[u].size();i++){
			v=g[u][i];in[v]--;
			if(in[v]==0){
				Q.push(v);
			}
		  }
		}else{
		   cnt++;
		   while(!Q.empty()){	
			   u=Q.front();Q.pop();
			   c[u]=cnt;S.push(u);
			   //cout<<u<<" "<<c[u]<<endl;
		   }
		}
	}
	for(i=1;i<=n+m;i++){
		u=fin(i);
		if(in[u]>0){cout<<"No";return 0;}
	}
	cout<<"Yes"<<endl;
	for(i=1;i<=n+m;i++){
		u=fin(i);
		cout<<c[u]<<" ";
		if(i==n)cout<<endl;
	}
}
原文地址:https://www.cnblogs.com/VIrtu0s0/p/10509743.html