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

Posted 日拱一卒 功不唐捐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj千题计划232:bzoj4727: [POI2017]Turysta相关的知识,希望对你有一定的参考价值。

http://www.lydsy.com/JudgeOnline/problem.php?id=4727

 

竞赛图tarjan缩点后得到的拓扑图一定是一条链

因为竞赛图任意两点的前后顺序确定,只有一种拓扑序列

 

竞赛图tarjan缩完点后,若出现强联通分量A和B

那么A中所有点 和 B中所有点的连边 要么全指向A中所有点,要么全指向B中所有点

否则A和B就是一个强联通分量

所以把缩完点之后按点的入度从小到大排序,即可得到竞赛图的拓扑序列

 

在这个拓扑序列上,可以从前面的强联通分量中任意一个点出来,到达后面的强联通分量的任意一个点

因为竞赛图的任意强联通子图存在一条哈密顿回路

 

那么再求出每个强联通分量的哈密顿回路

枚举起点,先把起点所在的哈密顿回路扔进栈,然后再按拓扑序把后面的哈密顿回路扔进栈,输出即可

 

#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 :  );
        }
    }
}    

 

以上是关于bzoj千题计划232:bzoj4727: [POI2017]Turysta的主要内容,如果未能解决你的问题,请参考以下文章

bzoj千题计划197:bzoj4247: 挂饰

bzoj千题计划118:bzoj1028: [JSOI2007]麻将

bzoj千题计划165:bzoj5127: 数据校验

bzoj千题计划144:bzoj1176: [Balkan2007]Mokia

bzoj千题计划177:bzoj1858: [Scoi2010]序列操作

bzoj千题计划142:bzoj3144: [Hnoi2013]切糕