C. League of Leesins(拓扑,规律,详解)

通往胜利(题目)的传送门

\(这题其实就是一个拓扑排序啦\)~~~

\(对于一个三元组(q,w,e)\)

\(我们连一条q-w,q-e的边,然后对w和e也这样连边\)

\(那么统计入度(也就是被几个三元组包含)\)
\(发现入度为1的点只有两个(一头一尾)\)

\(举个例子一个排列\)
排列:2 3 4 5 6 1
入度:1 2 3 3 2 1
\(初始把入度为1的一个入队,比如q.push(2)\)

\(由于2和3连边,2和4连边,那么2和4的入度都减1\)

\(此时3的入度变成1,3入队,一直重复下去.......\)

\(\color{Red}{但是这样会发现样例都过不去......}\)

\(原因一次拓扑操作中可能有多个数入度变为1入队\)

\(那么这个时候我们要把初始入度为3的优先入队,初始入度为2的稍后入队\)

\(至于为什么......入度为3变成1说明前面两个数都输出了,自己也必须马上输出\)

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+9;
int vis[maxn],n;
vector<int>vec[maxn];
queue<int>q;
bool find(int q,int w)
{
	for(int i=0;i<vec[q].size();i++)
		if(vec[q][i]==w)	return false;
	return true;
}
void jin(int q,int w,int e)
{
	vis[q]++;//增加入度 
	if(find(q,w))	vec[q].push_back(w);
	if(find(q,e)) vec[q].push_back(e);
}
bool com(int a,int b){
	return vis[a]>vis[b];
}
int main()
{
	cin>>n;
	for(int i=1;i<=n-2;i++)
	{
		int q,w,e;
		scanf("%d%d%d",&q,&w,&e);
		jin(q,w,e);jin(w,q,e);jin(e,q,w);
	}
	for(int i=1;i<=n;i++)	sort(vec[i].begin(),vec[i].end(),com);//入度大的在前面 
	int pre=0,last=0;
	for(int i=1;i<=n;i++)
	{
		if(!pre&&vis[i]==1)	pre=i;
		else if(pre&&vis[i]==1)	last=i;
	}
	q.push(pre);
	while(!q.empty())
	{
		int now=q.front();q.pop();
		printf("%d ",now);
		for(int i=0;i<vec[now].size();i++)
			if(--vis[vec[now][i]]==1)	q.push(vec[now][i]);
	}
	cout<<last;
} 

猜你喜欢

转载自www.cnblogs.com/iss-ue/p/12893070.html