[DFS][拓扑排序] Codeforces 1282E The Cake Is a Lie
题目大意
给你一个凸\(N\)边形,每个顶点都有一个编号,但顶点编号的顺序未知。给你该凸\(N\)边形拆分成的\(N-2\)个三角形的顶点的编号,让你求该凸多边形顶点编号的顺序,和依次切出这\(N-2\)个三角形的顺序。\(3 \leq N \leq 10^5\)。
题解
容易发现,在多边形内部的边均被两个三角形使用,在多边形轮廓上的边只被一个三角形使用,那么哈希一下,将只使用过一次的边的两个端点连线,形成一个环,DFS一下即得出多边形顶点编号的顺序。
对于两个三角形,如果它们有一条公共边,则将这两个三角形的编号连边,容易发现,这形成了一棵树。那么就类似于拓扑排序的做法,不断去删度数小于等于1的点,然后去更新与它相邻的点的度数,如此循环,即得到切下三角形的顺序。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <map>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
struct triangle{int a,b,c;};
triangle Data[500010];
map<pair<int,int>,pair<int,int> > Hash;
struct edge{int Next,to;};
edge G[2000010],G2[2000010];
int head[500010],head2[500010],Degree[500010];
bool vis[500010];
vector<int> AnsA,AnsB;
int T,N,cnt=2,cnt2=2;
inline void Add_Edge(int u,int v){
G[cnt].to=v;
G[cnt].Next=head[u];
head[u]=cnt++;
}
inline void Add_Edge2(int u,int v){
G2[cnt2].to=v;
G2[cnt2].Next=head2[u];
head2[u]=cnt2++;
}
inline void Insert(int i){
auto A=make_pair(min(Data[i].a,Data[i].b),max(Data[i].a,Data[i].b));
auto B=make_pair(min(Data[i].b,Data[i].c),max(Data[i].b,Data[i].c));
auto C=make_pair(min(Data[i].a,Data[i].c),max(Data[i].a,Data[i].c));
auto HA=Hash[A],HB=Hash[B],HC=Hash[C];
if(!HA.first) HA.first=i;
else HA.second=i;
if(!HB.first) HB.first=i;
else HB.second=i;
if(!HC.first) HC.first=i;
else HC.second=i;
Hash[A]=HA;Hash[B]=HB;Hash[C]=HC;
return;
}
inline void Init(){
Hash.clear();
cnt=cnt2=2;
fill(head,head+N+5,0);
fill(head2,head2+N+5,0);
fill(vis+1,vis+N+1,0);
fill(Degree,Degree+N+5,0);
AnsA.clear();AnsB.clear();
return;
}
void DFSA(int u){
vis[u]=true;
AnsA.push_back(u);
for(int i=head2[u];i;i=G2[i].Next){
int v=G2[i].to;
if(vis[v]) continue;
DFSA(v);
}
return;
}
queue<int> Q;
void TopSort(){
while(!Q.empty()) Q.pop();
fill(vis,vis+N+5,0);
for(RG i=1;i<=N-2;++i)
if(Degree[i]<=1) {Q.push(i);vis[i]=true;}
while(!Q.empty()){
int u=Q.front();Q.pop();
AnsB.push_back(u);
for(int i=head[u];i;i=G[i].Next){
int v=G[i].to;
if(vis[v]) continue;
--Degree[v];
if(Degree[v]<=1){vis[v]=true;Q.push(v);}
}
}
return;
}
int main(){
Read(T);
while(T--){
Read(N);
Init();
for(RG i=1;i<=N-2;++i){
Read(Data[i].a);
Read(Data[i].b);
Read(Data[i].c);
Insert(i);
}
for(auto it:Hash){
if(!it.second.second){
Add_Edge2(it.first.first,it.first.second);
Add_Edge2(it.first.second,it.first.first);
}
else{
Add_Edge(it.second.first,it.second.second);
Add_Edge(it.second.second,it.second.first);
++Degree[it.second.first];
++Degree[it.second.second];
}
}
DFSA(1);
TopSort();
for(RG i=0;i<(int)AnsA.size();++i){
printf("%d",AnsA[i]);
if(i<(int)AnsA.size()-1) printf(" ");
}
printf("\n");
for(RG i=0;i<(int)AnsB.size();++i){
printf("%d",AnsB[i]);
if(i<(int)AnsB.size()-1) printf(" ");
}
printf("\n");
}
return 0;
}