[cf1656I]Neighbour Ordering
显然每个点双独立,不妨分别考虑(特判两点一边的情况):
必要条件1:任意两点间不存在三条长度$\ge 2$且两两不交的简单路径
若存在,记点集分别为$\{a_{i}\},\{b_{i}\}$和$\{c_{i}\}$,用$[x_{1}<_{x_{2}}x_{3}]$表示"方向"
根据抽屉原理,存在两条路径"方向"相同,进而两者所构成的环即矛盾
必要条件2:原图(指点双)存在哈密顿回路
若不存在,取最长的简单环,并取一条形如$(环上,环外)$的边$(A,B)$
删去$A$后,取$B$到环上极近(不经过环上其余点)的点$C$,并分类讨论:
1.若$A$与$C$相邻,则可以将$(A,B)+(B\rightarrow C)$加入其中,与环最长矛盾
2.若$A$与$C$不相邻,则$A$和$C$间存在$\begin{cases}环上的两条路径\\(A,B)+(B\rightarrow C)\end{cases}$,不满足必要条件1,矛盾
求出哈密顿回路后,将所有点按回路的顺序重新编号
充要条件:不存在两条边$(i_{1},i_{2})$和$(j_{1},j_{2})$,满足$i_{1}<j_{1}<i_{2}<j_{2}$
充分性:若不存在,将每个点的出边按顺时针距离依次编号即可
必要性:若存在,对其分类讨论——
1.若仅有这$4$个点(即为$K_{4}$),不妨假设$2 <_{1}3<_{1}4$
分析三元环$(2-)1-3-2$,可得$1<_{3}2$
分析四元环$4-1-3-2$,注意到同时有$3<_{1}4$和$1<_{3}2$,即矛盾
2.若存在其余点,不妨假设某点在$i_{1}$到$j_{1}$的路径上
此时,$i_{1}$和$j_{1}$间存在$\begin{cases}(i_{1},i_{1}+1)+...+(j_{1}-1,j_{1})\\(i_{1},i_{2})+(i_{2},i_{2}-1)+...+(j_{1}+1,j_{1})\\(i_{1},i_{1}-1)+...+(j_{2}+1,j_{2})+(j_{2},j_{1})\end{cases}$,不满足必要条件1,矛盾
条件的判定和解的构造均简单,问题即如何求哈密顿回路:
在合法的图中,总存在一个二度点,将该点删除并连接相邻两点
重复此过程(直至两点一边),以这两点基础,依次将删除的点插入回路即可
而在不合法的图中,总会出现以下两种情况之一:
1.最终未得到两点一边的情况
2.某次插入时,(删除时)所相邻的两点在回路中不相邻
以此判定即可,时间复杂度为$o(n\log n)$,可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300005 4 int t,n,m,q,x,y,tmp,dfn[N],low[N],st[N],bl[N],K[N],nex[N],id[N]; 5 vector<int>e[N],V[N],ans[N];vector<pair<int,int> >E[N]; 6 pair<int,int>adj[N];queue<int>Q;set<int>S[N]; 7 bool cmp(int x,int y){ 8 return ((tmp<id[x])==(tmp<id[y]) ? id[x]<id[y] : tmp<id[x]); 9 } 10 void dfs(int k,int fa){ 11 dfn[k]=low[k]=++dfn[0],st[++st[0]]=k; 12 for(int i:e[k]) 13 if (i!=fa){ 14 if (dfn[i])low[k]=min(low[k],dfn[i]); 15 else{ 16 dfs(i,k),low[k]=min(low[k],low[i]); 17 if (dfn[k]<=low[i]){ 18 V[++q]=vector<int>{k}; 19 while (V[q].back()!=i){ 20 bl[st[st[0]]]=q; 21 V[q].push_back(st[st[0]--]); 22 } 23 } 24 } 25 } 26 } 27 int main(){ 28 scanf("%d",&t); 29 while (t--){ 30 scanf("%d%d",&n,&m); 31 for(int i=1;i<=n;i++)e[i].clear(); 32 for(int i=1;i<=m;i++){ 33 scanf("%d%d",&x,&y),x++,y++; 34 e[x].push_back(y),e[y].push_back(x); 35 } 36 q=0; 37 for(int i=0;i<=n;i++)dfn[i]=0; 38 for(int i=1;i<=n;i++) 39 if (!dfn[i])dfs(i,0); 40 for(int i=1;i<=q;i++)E[i].clear(); 41 for(int i=1;i<=n;i++) 42 for(int j:e[i]) 43 if (dfn[i]>dfn[j])E[bl[i]].push_back(make_pair(i,j)); 44 bool flag=0; 45 for(int i=1;i<=n;i++)ans[i].clear(); 46 for(int i=1;i<=q;i++){ 47 for(int j:V[i])e[j].clear(),S[j].clear(); 48 for(pair<int,int> j:E[i]){ 49 x=j.first,y=j.second; 50 e[x].push_back(y),e[y].push_back(x); 51 S[x].insert(y),S[y].insert(x); 52 } 53 K[0]=0; 54 for(int j:V[i]) 55 if (S[j].size()==2)Q.push(j); 56 while (!Q.empty()){ 57 int k=Q.front();Q.pop(); 58 if (S[k].size()!=2)continue; 59 x=(*S[k].begin()),y=(*++S[k].begin()); 60 K[++K[0]]=k,adj[K[0]]=make_pair(x,y); 61 S[k].clear(),S[x].erase(k),S[y].erase(k); 62 S[x].insert(y),S[y].insert(x); 63 if (S[x].size()==2)Q.push(x); 64 if (S[y].size()==2)Q.push(y); 65 } 66 if (K[0]+2!=V[i].size()){flag=1;break;} 67 x=y=0; 68 for(int j:V[i]){ 69 nex[j]=j; 70 if (S[j].size()==1)(x ? y : x)=j; 71 } 72 nex[x]=y,nex[y]=x; 73 for(int j=K[0];j;j--){ 74 int k=K[j],x=adj[j].first,y=adj[j].second; 75 if (nex[x]!=y)swap(x,y); 76 if (nex[x]!=y){flag=1;break;} 77 nex[x]=k,nex[k]=y; 78 } 79 if (flag)continue; 80 for(int j=V[i][0],k=0;k<V[i].size();j=nex[j],k++)id[j]=k; 81 for(int j:V[i]){ 82 tmp=id[j],sort(e[j].begin(),e[j].end(),cmp); 83 for(int k:e[j])ans[j].push_back(k); 84 } 85 } 86 if (flag)printf("NO\n"); 87 else{ 88 printf("YES\n"); 89 for(int i=1;i<=n;i++){ 90 for(int j:ans[i])printf("%d ",j-1); 91 printf("\n"); 92 } 93 } 94 } 95 return 0; 96 }