bzoj4727: [POI2017]Turysta(竞赛图构建哈密顿回路)
http://www.lydsy.com/JudgeOnline/problem.php?id=4727
竞赛图tarjan缩点后得到的拓扑图一定是一条链
因为竞赛图任意两点的前后顺序确定,只有一种拓扑序列
竞赛图tarjan缩完点后,若出现强联通分量A和B
那么A中所有点 和 B中所有点的连边 要么全指向A中所有点,要么全指向B中所有点
否则A和B就是一个强联通分量
所以把缩完点之后按点的入度从小到大排序,即可得到竞赛图的拓扑序列
在这个拓扑序列上,可以从前面的强联通分量中任意一个点出来,到达后面的强联通分量的任意一个点
因为竞赛图的任意强联通子图存在一条哈密顿回路
那么再求出每个强联通分量的哈密顿回路
枚举起点,先把起点所在的哈密顿回路扔进栈,然后再按拓扑序把后面的哈密顿回路扔进栈,输出即可
如何在竞赛图哈密顿路径的基础上构造回路,详请参见博客http://www.cnblogs.com/TheRoadToTheGold/p/8439160.html
#include<cstdio> #include<vector> #include<iostream> #include<algorithm> using namespace std; #define N 2001 int n; bool mp[N][N]; int tot; int dfn[N],low[N]; int st[N],top; bool vis[N]; int cnt; int id[N]; vector<int>scc[N]; int nxt[N]; int pos[N],in[N]; template<typename T> void read(T &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void tarjan(int x) { dfn[x]=low[x]=++tot; st[++top]=x; vis[x]=true; for(int i=1;i<=n;++i) { if(!mp[x][i]) continue; if(!dfn[i]) { tarjan(i); low[x]=min(low[x],low[i]); } else if(vis[i]) low[x]=min(low[x],dfn[i]); } if(low[x]==dfn[x]) { cnt++; while(st[top]!=x) { scc[cnt].push_back(st[top]); id[st[top]]=cnt; vis[st[top--]]=false; } scc[cnt].push_back(x); id[x]=cnt; vis[x]=false; top--; } } bool cmp(int a,int b) { return in[a]<in[b]; } void insert(int x) { st[++top]=x; for(int i=nxt[x];i && i!=x;i=nxt[i]) st[++top]=i; } int main() { read(n); for(int i=1;i<n;++i) for(int j=1;j<=i;++j) { read(mp[j][i+1]); mp[i+1][j]=mp[j][i+1]^1; } for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); for(int now=1;now<=cnt;++now) { int siz=scc[now].size(); int l,r; l=r=scc[now][0]; for(int i=1,t;i<siz;++i) { t=scc[now][i]; if(mp[t][l]) nxt[t]=l,l=t; else if(mp[r][t]) nxt[r]=t,r=t; else { for(int j=l;j;j=nxt[j]) if(mp[j][t] &&mp[t][nxt[j]]) { nxt[t]=nxt[j]; nxt[j]=t; break; } } } r=0; for(int i=nxt[l];i;i=nxt[i]) if(r) { for(int j=r,k=l;;k=j,j=nxt[j]) { if(mp[i][j]) { nxt[k]=nxt[l]; if(k!=l) nxt[l]=r; l=i; r=j; break; } if(j==l) break; } } else if(mp[i][l]) r=l,l=i; nxt[l]=r; } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(id[i]!=id[j] && mp[i][j]) in[id[j]]++; for(int i=1;i<=cnt;++i) { pos[i]=i; in[i]/=scc[i].size(); } sort(pos+1,pos+cnt+1,cmp); for(int i=1;i<=n;++i) { top=0; insert(i); for(int j=1,t;j<=cnt;++j) if(in[t=pos[j]]>in[id[i]]) insert(scc[t][0]); printf("%d ",top); for(int j=1;j<=top;++j) { printf("%d",st[j]); putchar(j==top ? '\n' : ' '); } } }