您的位置:首页 > 其它

bzoj千题计划232:bzoj4727: [POI2017]Turysta

2018-02-11 11:43 267 查看
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

;

int tot;
int dfn
,low
;
int st
,top;
bool vis
;

int cnt;
int id
;
vector<int>scc
;

int nxt
;

int pos
,in
;

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' : ' ');
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: